I'm trying to replicate the Photoshop filter multiply with Direct3D. I've been reading and googling about the different render states and I've got the effect almost working. The problem is that it's ignoring the alpha value of the textures.
Here's an image that explains the sitution:
http://www.kloonigames.com/petri/stackoverflow_doesnt_allow_.jpg
I found one solution to this, which was to save the images with no transparency and white background. But I'm not satisfied with this solution. The problem is that I really need to use the alpha value. I want to fade out the images gradually. And I cannot do this if the blending mode is ignoring the alpha value.
So the question is how to render the images with alpha?
Here's the blending mode code:
dev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
dev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
dev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR);
Edit added the SetTextureStageState
dev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
dev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
dev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
dev->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
You can achieve this effect in one step by premultipling alpha in your pixel shader, or by using textures with pre-multiplied alpha.
For example if you have 3 possible blend operations for a shader, and you want each one to take alpha into account.
Blend = ( src.rgb * src.a ) + ( dest.rgb * (1-src.a) )
Add = ( src.rgb * src.a ) + ( dest.rgb )
Multiply = (src.rgb * dest.rgb * src.a) + (dest.rgb * (1-src.a) )
You'll notice that Multiply is impossible with a single pass because there are two operations on the source color. But if you premultiply alpha in your shader you can extract the alpha component from the blending operation and it becomes possible to blend all three operations in the same shader.
In your pixel shader you can pre-multiply alpha manually. Or use a tool like DirectXTex texconv to modify your textures.
return float4(color.rgb*color.a, color.a);
The operations become:
Blend = ( src.rgb ) + ( dest.rgb * (1-src.a) )
Add = ( src.rgb ) + ( dest.rgb )
Multiply = ( src.rgb * dest.rgb ) + (dest.rgb * (1-src.a) )
It sounds like you want:
dst.rgb = (src.a * src.rgb) * ((1 - src.a) * dst.rgb)
You would use D3DRS_BLENDOP to do that, but unfortunately there isn't a D3DBLENDOP_MULTIPLY. I don't think this operation is possible without a fragment shader.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With