Direct3D的渲染2D图像与“乘”混合模式和阿尔法(Direct3D rendering 2D

2019-08-31 17:21发布

我试图复制Photoshop滤镜乘法与Direct3D的。 我一直在阅读和谷歌上搜索有关不同渲染状态和我有差不多的工作效果。 问题是,它忽略了纹理的Alpha值。

下面是解释sitution的图像:

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);

编辑添加的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);

Answer 1:

你可以在你的像素着色器,或通过使用纹理与预乘阿尔法premultipling阿尔法实现一步到位这种效果。

例如,如果你有3种可能的混合操作着色器,并希望每个人把阿尔法考虑。

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) )

你会发现,乘法是不可能的单程因为对源颜色两种操作。 但是,如果你在你的着色器预乘阿尔法,你可以提取混合操作的alpha分量,并有可能以混合所有三个操作在同一个着色器。

在您的像素着色器,你可以手动预乘阿尔法。 或使用像DirectXTex texconv一个工具来修改你的纹理。

return float4(color.rgb*color.a, color.a);

操作便会变得:

Blend = ( src.rgb ) + ( dest.rgb * (1-src.a) )
Add = ( src.rgb ) + ( dest.rgb )
Multiply = ( src.rgb * dest.rgb ) + (dest.rgb * (1-src.a) )


Answer 2:

这听起来像你想:

dst.rgb = (src.a * src.rgb) * ((1 - src.a) * dst.rgb)

你可以使用D3DRS_BLENDOP要做到这一点,但遗憾的是没有一个D3DBLENDOP_MULTIPLY。 我不认为这个操作可能没有一个片段着色器。



Answer 3:

好了,这是不是你想象的那么简单。 我会用的效果及2个renderTargets这个......我是你使用一个渲染过程,以尽量做到这一点,这是行不通的会哄。 Photoshop有层&每个层具有alpha通道。 BTW它会很高兴地知道什么样的应用程序的决策。

因此,首先在D3D我会创建一个同样大小的2个RGBA_32bit renderTargets作为你的窗口和清除它们以白色。 使它像这样(新的RenderTarget [2])的阵列用于交换。

现在设置混合状态(AlphaFunc =添加,SRC = SrcAlpha,Dst的= InvSrcAlpha)。 对于第一圆您使用的RenderTarget [1]作为纹理/采样输入源[0]绘制成的RenderTarget。 你会渲染,将采取圆圈的颜色及与渲染目标[1]的采样颜色相乘效果的圆。 绘制一个圆后只需更换的RenderTarget [0]与渲染目标[1]通过简单的索引,所以现在的RenderTarget [1]是在绘制到&的RenderTarget [0]是从采样一个所述一个。 然后你重复绘制过程圈2等等。

之后你画过圈出你的最后绘制的渲染目标复制到后备缓冲和呈现的场景。

这里是你会在逻辑上是如何做到这一点的例子。 如果您需要的编码参考http://www.codesampler.com/是个好地方。

void TestLayering()
{
bool rtIndex = false;
RenderTarget* renderTarget = new RenderTarget[2];
Effect effect = new Effect("multiplyEffect.fx");
effect.Enable();
BlendingFunc = Add;
BlendingSource = SrcAlpha;
BlendingDest = InvSrcAlpha;

for(int i = 0; i != circleCount; ++i)
{
  renderTarget[rtIndex].EnableAsRenderTarget();
  renderTarget[!rtIndex].EnableAsSampler();
  circle[i].Draw();
  rtIndex = !rtIndex;
}

//Use D3D9's StretchRect for this...
backBuffer.CopyFromSurface(renderTarget[rtIndex]);
}

//Here is the effects pixel shader
float4 PS_Main(InStruct In) : COLOR
{
float4 backGround = tex2D(someSampler, In.UV);
return circleColor * backGround;
}


Answer 4:

dev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR);
dev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

会做的伎俩。 您不能使用从漫顶点颜色的“阿尔法”了,虽然。 在顶点颜色设置低阿尔法实际上将照亮你的覆盖像素。



文章来源: Direct3D rendering 2D images with “multiply” blending mode and alpha