How can I do this blend effect?
BlitzMax Forums/BlitzMax Programming/How can I do this blend effect?
| ||
THIS IS DRIVING ME AROUND THE BEND I have these two terrains And this mask I want a result like this However, even where the mask is totally black the grass is contaminated somewhat by the sand image. I did it by experimenting and got this SetBlend ALPHABLEND DrawImage grass, 0, 0 SetBlend LIGHTBLEND DrawImage mask, 0, 0 SetBlend SHADEBLEND DrawImage sand, 0, 0 How can I do this properly using normal Max2d without using grab image? I just want to draw two images on top of each other displaying either one or the other or a mixture of the two according to a monochrome mask. WHY CAN'T I DO THIS! Thanks. Last edited 2011 Last edited 2011 |
| ||
Have you tried making that mask texture fully black or fully white in the RGB channels, and then using that gradient as its alpha channel? Then draw the mask with ALPHABLEND as well (so you just need a single call for both the grass and the mask), and then test either LIGHT or SHADE blends for the sand. You shouldn't use color-blending like you are now because the middle of the resulting composite texture is a bit desaturated from the blending with gray. If you use alpha blending with a flat-colored mask texture it should preserve the smooth result and the coloring too (even though the mask texture is flatly colored, its alpha channel gives the smooth transition). |
| ||
I've tried that but it doesn't work. The mask has its gradient in the alpha channels. It only draws the sand at the end. Could you post code like from my one above to explain how I should do this? Thanks. |
| ||
This is basically texture splatting in 2D, isn't it? I don't think you can do it in normal Max2D. It would require blend modes which Max doesn't expose. Or does Max2D now expose more blend modes? Are you able to set the source and destination blend modes separately? |
| ||
I have no idea. I can't even figure out how to draw rectangles in GIMP at the moment, let alone alpha transparency. I think that is why my mask wasn't working. |
| ||
Even with the mask in the alpha channel, when I draw the sand, it is still going over the pure grass region and making it appear too yellow. |
| ||
Can I use GRAPHICS_ALPHABUFFER to do this? Draw the first image solidly, draw the alpha mask to the alpha buffer, and then draw the second image in alpha blend? |
| ||
Well that's what I had in mind, yes. But you would definitely need full control over the source and destination blend modes. I'm sure I've seen some kind of addon which extended the blend modes available, but I can't find it offhand. |
| ||
I'VE DONE IT I'VE DONE IT I'VE DONE IT I'VE DONE IT I'VE DONE IT I'VE DONE IT I'VE DONE IT I'VE DONE IT I'VE DONE IT I'VE DONE IT I'VE DONE IT I'VE DONE IT I'VE DONE IT I'VE DONE IT I'VE DONE IT I'VE DONE IT I'VE DONE IT I'VE DONE IT I'VE DONE IT I've had to make some changes to max2d. First of all you will need to enable GRAPHICS_ALPHABUFFER. Then you will need to draw the alpha mask so that its alpha values are input directly onto the buffer. I called this direct blend. The other blend methods don't write to alpha. Then I made blend functions to write the image according to the destination alpha, which are the values from the mask. There are two versions of this blend. The second version inverts the alpha. I made this change to driver.bmx 'modes for SetBlend Const MASKBLEND=1 Const SOLIDBLEND=2 Const ALPHABLEND=3 Const LIGHTBLEND=4 Const SHADEBLEND=5 Const DIRECTBLEND=6 Const MASKONBLEND=7 Const MASKOFFBLEND=8 I made this change to glmax2d.bmx Method SetBlend( blend ) If blend=state_blend Return state_blend=blend Select blend Case MASKBLEND glDisable GL_BLEND glEnable GL_ALPHA_TEST glAlphaFunc GL_GEQUAL,.5 Case SOLIDBLEND glDisable GL_BLEND glDisable GL_ALPHA_TEST Case ALPHABLEND glEnable GL_BLEND glBlendFunc GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA glDisable GL_ALPHA_TEST Case LIGHTBLEND glEnable GL_BLEND glBlendFunc GL_SRC_ALPHA,GL_ONE glDisable GL_ALPHA_TEST Case SHADEBLEND glEnable GL_BLEND glBlendFunc GL_DST_COLOR,GL_ZERO glDisable GL_ALPHA_TEST Case DIRECTBLEND glEnable GL_BLEND glBlendFunc GL_ONE,GL_ZERO glDisable GL_ALPHA_TEST Case MASKONBLEND glEnable GL_BLEND glBlendFunc GL_DST_ALPHA,GL_ONE_MINUS_DST_ALPHA glDisable GL_ALPHA_TEST Case MASKOFFBLEND glEnable GL_BLEND glBlendFunc GL_ONE_MINUS_DST_ALPHA,GL_DST_ALPHA glDisable GL_ALPHA_TEST Default glDisable GL_BLEND glDisable GL_ALPHA_TEST End Select End Method Here is my user code Strict Const folder:String = "C:\SVN\trunk\Omega Directive\Temp\" MainF() Function MainF() SetGraphicsDriver(GLMax2DDriver(), GRAPHICS_BACKBUFFER | GRAPHICS_ALPHABUFFER) Graphics 512, 512 Local grass:TImage = LoadImage(folder + "Grass1.png", 0) Local sand:TImage = LoadImage(folder + "Sand1.png", 0) Local mask:TImage = LoadImage(folder + "Mask5.png", 0) While Not (KeyDown(KEY_ESCAPE) Or AppTerminate()) Cls SetBlend DIRECTBLEND DrawImage mask, 0, 0 SetBlend MASKONBLEND DrawImage grass, 0, 0 SetBlend MASKOFFBLEND DrawImage sand, 0, 0 Flip Delay 1 Wend End Function End Here is the result! Thanks to all that helped, including a number of old threads I read. Final part - how to add this for DirectX? The function for DX9 is this one, but I haven't looked up the parameters to change for this one. Method SetBlend( blend ) If blend=_active_blend Return Select blend Case SOLIDBLEND _d3dDev.SetRenderState D3DRS_ALPHATESTENABLE,False _d3dDev.SetRenderState D3DRS_ALPHABLENDENABLE,False Case MASKBLEND _d3dDev.SetRenderState D3DRS_ALPHATESTENABLE,True _d3dDev.SetRenderState D3DRS_ALPHABLENDENABLE,False Case ALPHABLEND _d3dDev.SetRenderState D3DRS_ALPHATESTENABLE,False _d3dDev.SetRenderState D3DRS_ALPHABLENDENABLE,True _d3dDev.SetRenderState D3DRS_SRCBLEND,D3DBLEND_SRCALPHA _d3dDev.SetRenderState D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA Case LIGHTBLEND _d3dDev.SetRenderState D3DRS_ALPHATESTENABLE,False _d3dDev.SetRenderState D3DRS_ALPHABLENDENABLE,True _d3dDev.SetRenderState D3DRS_SRCBLEND,D3DBLEND_SRCALPHA _d3dDev.SetRenderState D3DRS_DESTBLEND,D3DBLEND_ONE Case SHADEBLEND _d3dDev.SetRenderState D3DRS_ALPHATESTENABLE,False _d3dDev.SetRenderState D3DRS_ALPHABLENDENABLE,True _d3dDev.SetRenderState D3DRS_SRCBLEND,D3DBLEND_ZERO _d3dDev.SetRenderState D3DRS_DESTBLEND,D3DBLEND_SRCCOLOR End Select _active_blend=blend End Method |
| ||
Nice job! Although I can't really figure out why this would work-- unless the alpha buffer is filled first with $ff, which makes a little sense. It also gives strange artifacts when the color is either $ff or $00, but that could just be the images I'm using. |
| ||
Hi Adam, How does it work with the images I provide? This game will be publically distributed so I need to iron out any bugs. Please upload the images and mask you are using and I will test it my end. It doesn't matter what is in the alpha buffer as the direct blend mode will totally replace the value with that from the mask. Images you don't want to blend with a mask use one of the existing blend modes which ignore the alpha buffer anyway (I think, I've not tried integrated) I think I made some changes to the mask. The mask needs to be pure black with the transition in the alpha channel. Here is the mask I used. Hopefully its alpha channel won't get botched in the transfer. Last edited 2011 |
| ||
It's been a while since I worked with DX9 blend modes, but I think :Case MASKONBLEND glEnable GL_BLEND glBlendFunc GL_DST_ALPHA,GL_ONE_MINUS_DST_ALPHA glDisable GL_ALPHA_TEST Case MASKOFFBLEND glEnable GL_BLEND glBlendFunc GL_ONE_MINUS_DST_ALPHA,GL_DST_ALPHA glDisable GL_ALPHA_TEST would translate to Case MASKONBLEND _d3dDev.SetRenderState D3DRS_ALPHABLENDENABLE,True _d3dDev.SetRenderState D3DRS_ALPHATESTENABLE,False _d3dDev.SetRenderState D3DRS_SRCBLEND,D3DBLEND_DESTALPHA _d3dDev.SetRenderState D3DRS_DESTBLEND,D3DBLEND_INVDESTALPHA Case MASKOFFBLEND _d3dDev.SetRenderState D3DRS_ALPHABLENDENABLE,True _d3dDev.SetRenderState D3DRS_ALPHATESTENABLE,False _d3dDev.SetRenderState D3DRS_SRCBLEND,D3DBLEND_INVDESTALPHA _d3dDev.SetRenderState D3DRS_DESTBLEND,D3DBLEND_DESTALPHA I'm not 100% on how BlitzMax spells those constants, so you may have to replace DEST with DST. With DX9, they're supposed to be DEST but BlitzMax might have them as DST to provide consistency with OpenGL. |
| ||
@Czar: works fine with your images. |
| ||
Hi, this can be made without any extra blend modes, and this works with all drivers (dx7/9,opengl) http://www.byrathon.com/omat/blend.zip the trick is using "alpha only" mask image. make mask image and convert that to PF_A8 format. Local pix:TPixmap=LoadPixmap("filename.png") 'Load mask image SavePixmapPNG(ConvertPixmap(pix,PF_A8),"alpha_mask.png") 'convert and save mask image to PF_A8 (alpha only image) then you can draw images using only 2 blend modes: SuperStrict 'Blend effect SetGraphicsDriver D3D7Max2DDriver() 'SetGraphicsDriver D3D9Max2DDriver() 'SetGraphicsDriver GLMax2DDriver() Graphics 800,600 Global grass:TImage=LoadImage("grass.jpg") Global sand:TImage=LoadImage("sand.jpg") Global mask:TImage=LoadImage("alpha_mask.png") 'PF_A8 format While Not (KeyHit(KEY_ESCAPE) Or AppTerminate()) Cls SetBlend ALPHABLEND DrawImage grass,0,0 DrawImage mask,0,0 SetBlend ShadeBlend DrawImage sand,0,0 Flip Delay 1 Wend [EDIT] and if you want to use different color when drawing sand, you must set that color before drawing mask. and set color back to white when drawing sand. example: SuperStrict 'Blend effect SetGraphicsDriver D3D7Max2DDriver() SetGraphicsDriver D3D9Max2DDriver() 'SetGraphicsDriver GLMax2DDriver() Graphics 800,600 Global grass:TImage=LoadImage("grass.jpg") Global sand:TImage=LoadImage("sand.jpg") Global mask:TImage=LoadImage("alpha_mask.png") 'PF_A8 format While Not (KeyHit(KEY_ESCAPE) Or AppTerminate()) Cls SetColor 255,255,255 'Grass drawing color (white) SetBlend ALPHABLEND DrawImage grass,0,0 SetColor 0,255,0 'Sand drawing color (hreen) DrawImage mask,0,0 SetColor 255,255,255 'set WHITE color here SetBlend ShadeBlend DrawImage sand,0,0 Flip Delay 1 Wend Last edited 2012 |