Direct3D使用“乘法”混合模式和Alpha渲染2D图像

use*_*268 5 c++ photoshop graphics direct3d alphablending

我正在尝试将Photoshop滤镜复制为Direct3D。我一直在阅读和搜索不同的渲染状态,并且效果几乎可以正常工作。问题在于它忽略了纹理的Alpha值。

这是说明情况的图像:

http://www.kloonigames.com/petri/stackoverflow_doesnt_allow_.jpg

我找到了一种解决方案,那就是保存没有透明度和白色背景的图像。但是我对这种解决方案不满意。问题是我真的需要使用alpha值。我想逐渐淡出图像。如果混合模式忽略了alpha值,则无法执行此操作。

所以问题是如何用alpha渲染图像?

这是混合模式代码:

dev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
dev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
dev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR);
Run Code Online (Sandbox Code Playgroud)

编辑添加了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);
Run Code Online (Sandbox Code Playgroud)

Geo*_*son 5

您可以通过在像素着色器中预乘alpha或通过使用具有预乘alpha的纹理来一步实现此效果。

例如,如果您有3种可能的着色器混合操作,并且您希望每个着色器都考虑alpha。

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) )
Run Code Online (Sandbox Code Playgroud)

您会注意到,单次遍历是不可能实现乘法的,因为对源颜色有两项操作。但是,如果在着色器中预乘Alpha,则可以从混合操作中提取Alpha分量,并且可以在同一着色器中混合所有三个操作。

在像素着色器中,您可以手动预乘Alpha。或使用DirectXTex texconv之类的工具来修改纹理。

return float4(color.rgb*color.a, color.a);
Run Code Online (Sandbox Code Playgroud)

操作变为:

Blend = ( src.rgb ) + ( dest.rgb * (1-src.a) )
Add = ( src.rgb ) + ( dest.rgb )
Multiply = ( src.rgb * dest.rgb ) + (dest.rgb * (1-src.a) )
Run Code Online (Sandbox Code Playgroud)


小智 1

听起来你想要:

dst.rgb = (src.a * src.rgb) * ((1 - src.a) * dst.rgb)
Run Code Online (Sandbox Code Playgroud)

您可以使用 D3DRS_BLENDOP 来执行此操作,但不幸的是没有 D3DBLENDOP_MULTIPLY。我认为如果没有片段着色器,这个操作是不可能的。