Alpha blending with material

Started by
3 comments, last by CrazyCdn 17 years, 11 months ago
I'm experimenting with a particle system that supports rendering mesh particles. I've ran into problems with getting alpha blending to work the way I wish. I simply want the overall alpha of the mesh to be modulated by the material's alpha value (material's alpha states the overall visibility) and the same for color as well. I'm rendering the mesh using D3DX:s ID3DXMesh::DrawSubset. Render and texture states (lighting is enabled):

pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
pDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);

pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
pDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);

Now the problem is that while the alpha seems to work all the meshes render in black regardless of material color (if I use D3DTOP_SELECTARG1 for colorop then it works just fine with plain texture but I want to be able to modulate the color as well). And could someone explain those SRCBLEND and DESTBLEND? The documantation in MSDN library is pretty scarce telling next to nothing and they seem pretty essential.
Advertisement
Errant,

Sorry, my original post just looked like crap...so I'm going to scrap it and start over.

First, lets explore what you're currently doing, then we'll explore what you SHOULD be doing.
Quote:
pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
pDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);


Ok, with the above code you are enabling alpha blending. Then you're setting frame buffer alpha blending options. This relates to your question about SRCBLEND and DESTBLEND. Rather then try and explain it fully myself, I just repost the DirectX documentation, as I think it describes this best.
Quote:
Frame buffer alpha-blending is a bit different than vertex alpha, material alpha, and texture alpha. Vertex, material, and texture alpha set transparency values that are used only for the current primitive, and by themselves have no effect on other primitives. Frame buffer alpha-blending controls how the current primitive is combined with existing pixels in the frame buffer to yield a final pixel color.

When performing alpha blending, two colors are being combined: a source color and a destination color. The source color is from the transparent object, the destination color is the color already at the pixel location. The destination color is the result of rendering some other object that is behind the transparent object, that is, the object that will be visible through the transparent object. Alpha blending uses a formula to control the ratio between the source and destination objects.

Final Color = ObjectColor * SourceBlendFactor + PixelColor * DestinationBlendFactor

ObjectColor is the contribution from the primitive being rendered at the current pixel location. PixelColor is the contribution from the frame buffer at the current pixel location.

As your object is being rendered, the SRCBLEND and DESTBLEND flags are used to determine where the colors are coming from that will be used in the above equation. If you're not sure what the result will be, just use the formula above and calculate out yourself what the result color will be.

Lets take an example, based on the values you're setting.

With D3DRS_SRCBLEND = D3DBLEND_SRCALPHA your source factor will be equal to

SourceRGBA = Source_Red * Source_Alpha, Source_Green * Source_Alpha, Source_Blue * Source_Alpha, Source_Alpha * Source_Alpha;

With D3DRS_DESTBLEND = D3DBLEND_INVSRCALPHA your destination factor will be equal to

float invAlpha = 1 - Source_Alpha;
DestRGBA = Dest_Red * invAlpha, Dest_Green * invAlpha, Dest_Blue * invAlpha, Dest_Alpha * invAlpha;

The final color at any given pixel in the frame buffer will be those two colors added together, ie.

PixelColor = SourceRGBA + DestRGBA;

As you can see, if your alpha value is 0.5f, then your destination pixel color will be 0.5x every component of your source, plus 0.5x (1-0.5f) of your destination color. This, in general, should be just fine...and is the desired behavior you're looking for...sortof. This leads us to the next part of your code...
Quote:
pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
pDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);

In the above code you're telling the texture renderer that you want your alpha value to be pulled from the alpha component of your diffuse color?!?! My instincts tells me this is part of your problem. you said in your post that you want to pull the alpha value from the Material, not the vertex, but up until this point you've not changed where the diffuse color is pulled from, and its the vertex by default.

After that you tell the texture renderer that you want the diffuse color to come from the texture's pixels, modulated with the color that's in the diffuse color. Again, without specifying this has nothing to do with the material. In fact, you're likely trying to multiply (modulate) your texture colors by your vertex color. If the vertex color is black (0x00000000) then your final color will always be black.

Ok...so on to the likely solution. You need to tell the renderer that you want diffuse values to be pulled from the material, not the vertex. You can do that using the following:

m_pd3dDevice->SetRenderState( D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL );

Then create a material and set it on the renderer like so....

D3DMATERIAL9 mtrl;
mtrl.Diffuse = mtrl.Ambient = mtrl.Specular = mtrl.Emissive =
D3DCOLORVALUE(255,255,255,0.5f)

m_pd3dDevice->SetMaterial(&mtrl);

Now...the color and alpha value used will come from the material, rather then from the vertex.

Cheers and good luck!

[Edited by - jwalsh on May 5, 2006 7:45:38 PM]
Jeromy Walsh
Sr. Tools & Engine Programmer | Software Engineer
Microsoft Windows Phone Team
Chronicles of Elyria (An In-development MMORPG)
GameDevelopedia.com - Blog & Tutorials
GDNet Mentoring: XNA Workshop | C# Workshop | C++ Workshop
"The question is not how far, the question is do you possess the constitution, the depth of faith, to go as far as is needed?" - Il Duche, Boondock Saints
Make sure that you have lighting enabled, otherwise even if you change the material diffuse component to have a different color on the texture it will look black.

PS: No need to call this renderstate D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL
because if you have no Diffuse component specify in your vertex structure, and you have lighting enabled, Direct3D will automatically get the color from the material.
Thank you. That really cleared things up. And I also managed to solve the problem which was that I hadn't set emissive color for the material I used (!!). Now it works just as I intended and looks pretty nice (at least compared to the old system). Here's a screenie

[Edited by - Errant Knight on May 7, 2006 6:27:34 AM]
doesn't work here, you gotta use a standard html link. Below links to your picture just for whoever reads this in the future.

Linky to the picture

Edit: Looks good btw

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

This topic is closed to new replies.

Advertisement