Alpha Texture Cascade Woes
Hey All,
I''m trying to render a model with a texture and a black and white alpha texture. This is the texture cascade that I am using:
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCCOLOR);
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR);
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE);
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
g_pd3dDevice->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 0 );
g_pd3dDevice->SetTransform(D3DTS_WORLD, &worldm);
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );
g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT );
g_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
g_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
g_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
g_pd3dDevice->SetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_DISABLE);
g_pd3dDevice->SetTextureStageState( 2, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
But it doesn''t really work out. Can anyone see what is wrong?
So you want:
- Texture 0 = RGB
- Texture 1 = A
- Alpha blending of RGB with the RGB values already in the frame buffer based on the value of A
??
If so, your SetTextureStageState() calls are correct. However the frame buffer blend you''re asking for doesn''t use the alpha channel at all, and is a little odd too.
The frame buffer blend you''ve asked for (D3DRS_SRCBLEND & D3DRS_DESTBLEND) does the following:
RESULTrgb = (RENDEREDrgb * RENDEREDrgb) + (CURRENTrgb * RENDEREDrgb)
Where RENDEREDrgb is the RGB value of the pixel output from the multi texture cascade. CURRENTrgb is the RGB value of the pixel already in the frame buffer and RESULTrgb is the RGB value of what gets put into the frame buffer after the blend operation has completed.
About the only reason I can think of you wanting the above blend would be something like exponentiation for specular, but it definately won''t use your alpha value for anything.
What I suspect you probably want (for traditional transparency type alpha blending) is:
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
What that will do is more like a linear interpolation between what you''re rendering and what''s already in the frame buffer with your alpha value being used to control what level:
RESULTrgb = (RENDEREDa * RENDEREDrgb) + ((1-RENDEREDa) * CURRENTrgb)
Where RENDEREDrgb is the RGB value of the pixel output from the multi texture cascade. RENDEREDa is the ALPHA value of the pixel output from the multi texture cascade. CURRENTrgb is the RGB value of the pixel already in the frame buffer and RESULTrgb is the RGB value of what gets put into the frame buffer after the blend operation has completed.
That''s all assuming of course that you''ve taken care of all the usual transparency issues such as rendering your semi-transparent polygons at the correct time (i.e. after all the opaque stuff), with Z writes off (so that you can see pixels underneath the alpha pixels), with Z tests on (so your semi transparent stuff interacts correctly with stuff that has written to the Z buffer) and with any Z sorting of semi transparent objects/polygons done (so that transparent objects sort correctly with respect to themselves and other transparent objects).
If your alpha texture only represents 100% transparent or 100% opaque (i.e. pixel on or pixel off), then you don''t need to use alpha blending for that. You can use alpha test to reject those pixels instead.
--
Simon O''Connor
ex -Creative Asylum
Programmer &
Microsoft MVP
- Texture 0 = RGB
- Texture 1 = A
- Alpha blending of RGB with the RGB values already in the frame buffer based on the value of A
??
If so, your SetTextureStageState() calls are correct. However the frame buffer blend you''re asking for doesn''t use the alpha channel at all, and is a little odd too.
The frame buffer blend you''ve asked for (D3DRS_SRCBLEND & D3DRS_DESTBLEND) does the following:
RESULTrgb = (RENDEREDrgb * RENDEREDrgb) + (CURRENTrgb * RENDEREDrgb)
Where RENDEREDrgb is the RGB value of the pixel output from the multi texture cascade. CURRENTrgb is the RGB value of the pixel already in the frame buffer and RESULTrgb is the RGB value of what gets put into the frame buffer after the blend operation has completed.
About the only reason I can think of you wanting the above blend would be something like exponentiation for specular, but it definately won''t use your alpha value for anything.
What I suspect you probably want (for traditional transparency type alpha blending) is:
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
What that will do is more like a linear interpolation between what you''re rendering and what''s already in the frame buffer with your alpha value being used to control what level:
RESULTrgb = (RENDEREDa * RENDEREDrgb) + ((1-RENDEREDa) * CURRENTrgb)
Where RENDEREDrgb is the RGB value of the pixel output from the multi texture cascade. RENDEREDa is the ALPHA value of the pixel output from the multi texture cascade. CURRENTrgb is the RGB value of the pixel already in the frame buffer and RESULTrgb is the RGB value of what gets put into the frame buffer after the blend operation has completed.
That''s all assuming of course that you''ve taken care of all the usual transparency issues such as rendering your semi-transparent polygons at the correct time (i.e. after all the opaque stuff), with Z writes off (so that you can see pixels underneath the alpha pixels), with Z tests on (so your semi transparent stuff interacts correctly with stuff that has written to the Z buffer) and with any Z sorting of semi transparent objects/polygons done (so that transparent objects sort correctly with respect to themselves and other transparent objects).
If your alpha texture only represents 100% transparent or 100% opaque (i.e. pixel on or pixel off), then you don''t need to use alpha blending for that. You can use alpha test to reject those pixels instead.
--
Simon O''Connor
ex -Creative Asylum
Programmer &
Microsoft MVP
Hi Simon,
Thankyou so much for the detailed response. It seems as though I have everything correct. Though you were right about the blending states how I had them incorrect. The reason I had accidently set the D3DRS_DESTBLEND to D3DBLEND_SRCCOLOR was because it always seems to output the negetive of what it should in the areas that should be draws. Screenshots below
What I see
What I want to see
The texture
The alpha texture
I don''t understand why it looks the way it does. The blending cascade seems like it''s the way it should be.
~Wave
Thankyou so much for the detailed response. It seems as though I have everything correct. Though you were right about the blending states how I had them incorrect. The reason I had accidently set the D3DRS_DESTBLEND to D3DBLEND_SRCCOLOR was because it always seems to output the negetive of what it should in the areas that should be draws. Screenshots below
What I see
What I want to see
The texture
The alpha texture
I don''t understand why it looks the way it does. The blending cascade seems like it''s the way it should be.
~Wave
I don''t really know whats wrong, but I think the cascade is alright, although If the alpha texture that you showed us ther is your actual texture, then you have a problem.
Alpha values in textures determine transparency. So a transparent value in an image is not neccessarily white.
The format of the image you posted is jpg. to the point I know, they can''t handle alpha values (although I''m not sure).
And If the image was transparent we would see the background (which is black in the forum) so I think since the image has no alpha data, the alpha values are set to one and theres no
transparency . And thats why you don''t get your results.
If thats the problem, I''m not sure if I know the answer, and also I don''t know If thats the problem or not :-/ meh ... hehe
But you can try using another format (If jpg doesn''t support alpha transparency)
cheers
-Nims
www.users.bigpond.com/nimak
Alpha values in textures determine transparency. So a transparent value in an image is not neccessarily white.
The format of the image you posted is jpg. to the point I know, they can''t handle alpha values (although I''m not sure).
And If the image was transparent we would see the background (which is black in the forum) so I think since the image has no alpha data, the alpha values are set to one and theres no
transparency . And thats why you don''t get your results.
If thats the problem, I''m not sure if I know the answer, and also I don''t know If thats the problem or not :-/ meh ... hehe
But you can try using another format (If jpg doesn''t support alpha transparency)
cheers
-Nims
www.users.bigpond.com/nimak
Am I extracting the alpha value instead of the color? If that's the case is there any way to extract the color instead of the alpha for the alpha value of the previous texture stage?
~Wave
[edited by - Wavewash on July 7, 2003 3:56:06 AM]
~Wave
[edited by - Wavewash on July 7, 2003 3:56:06 AM]
hrrm ... the D3DTA_ALPHAREPLICATE puts the alpha values in the color values, but I don''t know if theres a reverse.
btw, you could use gif. They handle transparency. I hope DirectX reads them.
-Nims
www.users.bigpond.com/nimak
btw, you could use gif. They handle transparency. I hope DirectX reads them.
-Nims
www.users.bigpond.com/nimak
Aha!, Nims is right - I totally missed that (must''ve been half asleep) - alpha values need to be in the alpha channel to work with the multitexure setup you''ve got.
The best thing to do, if the format is supported on your target hardware is load the alpha texture into an alpha only format such as D3DFMT_A8.
There isn''t an explicit reverse of D3DTA_ALPHAREPLICATE because while going from 1 channel into 3 has "obvious" behaviour, going the other way from 3 channels into 1 is undefined.
The result of the D3DTOP_DOTPRODUCT3 operation goes into the alpha channel too, so you could use that to copy one of the colour channels (R, G or B) over into the alpha channel.
e.g.
RGB(0.4, 0.4, 0.4) DOT MASK(1.0, 0.0, 0.0) = 0.4
--
Simon O''Connor
ex -Creative Asylum
Programmer &
Microsoft MVP
The best thing to do, if the format is supported on your target hardware is load the alpha texture into an alpha only format such as D3DFMT_A8.
There isn''t an explicit reverse of D3DTA_ALPHAREPLICATE because while going from 1 channel into 3 has "obvious" behaviour, going the other way from 3 channels into 1 is undefined.
The result of the D3DTOP_DOTPRODUCT3 operation goes into the alpha channel too, so you could use that to copy one of the colour channels (R, G or B) over into the alpha channel.
e.g.
RGB(0.4, 0.4, 0.4) DOT MASK(1.0, 0.0, 0.0) = 0.4
--
Simon O''Connor
ex -Creative Asylum
Programmer &
Microsoft MVP
I got it to work with D3DTOP_DOTPRODUCT3 on a radeon 9700 but the problem is that this isn't practical since I would like to have compatability down to a voodoo3. And my Voodoo5500 machine says that it doesn't support DOTPRODUCT3. So I'm assuming a voodoo3 doesn't either.
Also the voodoo5500 doesn't support D3DFMT_A8 so that makes this all the more difficult. Any ideas on how to acheive this on older hardware?
I began to think maybe I could use a stencil buffer and render to it using the mask texture and then draw the regular texture but that seems like overkill for such a simple process. This effect is easily done in OpenGL, I don't understand why it's so difficult to reproduce in DirectX.
~Wave
[edited by - Wavewash on July 8, 2003 7:06:43 AM]
Also the voodoo5500 doesn't support D3DFMT_A8 so that makes this all the more difficult. Any ideas on how to acheive this on older hardware?
I began to think maybe I could use a stencil buffer and render to it using the mask texture and then draw the regular texture but that seems like overkill for such a simple process. This effect is easily done in OpenGL, I don't understand why it's so difficult to reproduce in DirectX.
~Wave
[edited by - Wavewash on July 8, 2003 7:06:43 AM]
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement