2009-10-23 52 views
4

我试图用Direct3D复制Photoshop滤镜乘法。我一直在阅读和搜索不同的渲染状态,我的效果几乎可以工作。问题是它忽略了纹理的alpha值。Direct3D呈现“乘”混合模式和alpha的2D图像

下面是解释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); 
+0

下面是渲染的完整源代码:http://pastebin.com/m7d7991fb – user35268 2009-10-23 13:53:12

+0

该链接不起作用... – zezba9000 2011-03-04 21:10:36

+0

你设置了什么纹理 - > SetTextureStageState – 2009-10-23 14:14:57

回答

1

这听起来像你想:

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

你会使用D3DRS_BLENDOP做,但不幸的是没有D3DBLEN DOP_MULTIPLY。没有片段着色器,我不认为这个操作是可能的。

0

好吧,这并不像您想象的那么简单。我会使用效果&两个renderTargets为此... 我很逗逗你使用一个渲染通道来尝试这样做,这是行不通的。 Photoshop有层&每层都有一个alpha通道。顺便说一句,它会很高兴知道你的作品是什么样的应用程序。

因此,首先在D3D中,我将创建2个与您的窗口尺寸相同的RGBA_32bit renderTargets,并将它们清除为白色。让它像这样(新的RenderTarget [2];)的数组交换。

现在将混合状态设置为(AlphaFunc = Add,Src = SrcAlpha,Dst = InvSrcAlpha)。对于第一个圆,您可以使用renderTarget [1]作为纹理/采样器输入源将其绘制到renderTarget [0]中。您将使用一个效果渲染该圆,该圆将颜色&乘以renderTarget [1]的采样器颜色。绘制圆形之后,通过简单索引将renderTarget [0]与renderTarget [1]交换,所以现在renderTarget [1]是您绘制到&的那个renderTarget [0]是您从中抽取的一个。然后你重复圆圈2的绘图过程,如此类推。

在你画圆圈后,你将最后绘制的renderTarget复制到backBuffer &当前的场景中。

下面是一个逻辑上如何做的例子。如果您需要参考编码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; 
} 
4

您可以通过在像素着色器中预乘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)) 

您会注意到,因为源颜色有两个操作,所以Multiply是不可能的。但是,如果您在着色器中预乘alpha,则可以从混合操作中提取alpha分量,并且可以在同一着色器中混合所有三个操作。

在您的像素着色器中,您可以手动预乘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)) 
0
dev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR); 
dev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); 

会做的伎俩。不过,您不能再使用漫反射顶点颜色中的'alpha'。在顶点颜色上设置较低的alpha值将实际上增亮您的重叠像素。