不得不说,这个是目前为止最为复杂的一个程序,不光是因为包含有很多的Pass,而且添加了很多的RenderTarget。每个Pass的功能倒是比较容易理解,但是要理清每个RenderTarget的功能就要费上一番功夫。因为本例中使用了7个RenderTarget(So Crazy),下面我们来说说每个RenderTarget的功能。
该程序一共使用了如图所示的RenderTarget,
其中 RenderTargetOriginal 表面大小等于ViewPort,
RenderTargetSmallTemp, Glow1, Glow2, Glow2A表面大小等于128×128,
Glow3和Glow3A大小等于64×64;
HDR Glare的绘制流程用语言比较难描述,于是我做了一幅图,一目了然。
关于最后一步的alpha混合,所采用的是D3DBLENDOP_ADD.
这是一个非常好的Alpha混合练习,如果对Alpha混合不了解,尝试一下改变StateBlock中的Alpha项的值,Alpha这块是我的弱项,因为我没有写过这方面的DEMO,只是看过相关资料。
D3DRS_ALPHABLENDENABLE:Alpha混合选项;
D3DRS_ALPHATESTENABLE:Alpha测试选项;
如果 D3DRS_ALPHATESTENABLE设置为FLASE(提前是 D3DRS_ALPHABLENDENABLE为TRUE),则ScrPixel不经过任何测试,直接与DestPixel进行混合;如果D3DRS_ALPHATESTENABLE设置为TRUE,这时就要进行Alpha测试了,我们就需要一个函数及一个掩码,即D3DRS_ALPHAFUNC(缺省值为D3DCMP_LESSEQUAL)及D3DRS_ALPHAREF(0x0),需要将ScrPixel的α与D3DRS_ALPHAREF值进行比较,比较成功(比较函数由D3DRS_ALPHAFUNC值来定),则接受该像素进行进一步混合,否则拒绝该像素混合。
假设我们通过了Alpha测试(包含 D3DRS_ALPHATESTENABLE设置为FLASE,也可认为是通过了测试),我们就需要对ScrPixel和DestPixel进行混合了。
the blend operator can be one of the following:
-
D3DBLENDOP_ADD: Sets the blending equation to:
OutputPixel= SourcePixel ⊗ SourceBlendFactor + DestPixel ⊗ DestBlendFactor
-
D3DBLENDOP_SUBTRACT: Sets the blending equation to:
OutputPixel = SourcePixel ⊗ SourceBlendFactor -DestPixel ⊗ DestBlendFactor
-
D3DBLENDOP_REVSUBTRACT: Sets the blending equation to:
OutputPixel = DestPixel ⊗ DestBlendFactor- SourcePixel ⊗ SourceBlendFactor
-
D3DBLENDOP_MIN: Sets the blending equation to:
OutputPixel = min(SourcePixel ⊗ SourceBlendFactor, DestPixel ⊗ DestBlendFactor)
-
D3DBLENDOP_MAX: Sets the blending equation to:
OutputPixel = max(SourcePixel ⊗ SourceBlendFactor, DestPixel ⊗ DestBlendFactor);
我们会发现我们还缺少SourceBlendFactor和DestBlendFactor,可以通过设置D3DBLEND来改变我们所需要的混合权重,一般设置为如下:
- D3DBLEND_SRCALPHA——Blend factor is (As, As, As, As).
- D3DBLEND_INVSRCALPHA——Blend factor is ( 1 - As, 1 - As, 1 - As, 1 - As).
- 好,以上是对Alpha混合进行一个回忆,现在我们来看在该例子中Alpha混合是如何进行的。
- 我们在最后一个Pass中计算三个RenderTarget的颜色之和,并将它们与BufferBack混合(注意:alpha混合是在Pixel Shader之后)。
- 代码如下:
1 sampler Texture0;
2 sampler Texture1;
3 sampler Texture2;
4 float Glow_Factor1;
5 float Glow_Factor2;
6 float Glow_Factor3;
7
8 float SourceAlpha;
9
10 float4 ps_main(float2 Tex : TEXCOORD0) : COLOR0
11 {
12 return
13 float4((tex2D(Texture0,Tex).xyz)*Glow_Factor1,SourceAlpha) +
14 float4((tex2D(Texture1,Tex).xyz)*Glow_Factor2,0) +
15 float4((tex2D(Texture2,Tex).xyz)*Glow_Factor3,0);
16 }
SourceAlpha在程序中取值为1。我们认为此时三个纹理混合在一起的RenderTarget为ScrPixel,而BufferBack现在为DestPixel,正好程序设置的是需要进行α混合,但不需要进行α测试,我们直接对源像素及目标像素进行混合,由于混合方法是D3DBLENDOP_ADD,我们采取如下公式:
OutputPixel= SourcePixel ⊗ SourceBlendFactor + DestPixel ⊗ DestBlendFactor
StateBlock中对SourceBlendFactor 设置为D3DBLEND_SCRALPHA,D3DBLEND_SRCALPHA: blendFactor = (as, as, as, as);
DestBlendFactor设置为D3DBLEND_ONE,D3DBLEND_ONE: blendFactor = (1, 1, 1, 1);
我们注意到ScrPixel的 blendFactor = (as, as, as, as) = (1,1,1,1)。如下图所示,因为,PREVIEW下的纹理的Alpha通道为白色,所以 blendFactor = (as, as, as, as) = (1,1,1,1)。
而DestPixel的 blendFactor = (1, 1, 1, 1)也等于(1,1,1,1),虽然它具备非1的alpha通道,但是我们并不使用它的alpha通道,因为在StateBlock中权重被设置为了D3DBLEND_ONE将如下图:
起初我有一个疑问,目标像素跟源像素的Blendfactor都为(1,1,1,1)了,混合结果岂不是很亮???
后来发现混合结果只是比DestPixel亮了一些,原因在于:
return float4((tex2D(Texture0,Tex).xyz)*Glow_Factor1,SourceAlpha) + float4((tex2D(Texture1,Tex).xyz)*Glow_Factor2,0) + float4((tex2D(Texture2,Tex).xyz)*Glow_Factor3,0);
语句中的Glow_Factor取值只有0.15左右,总共加起来,ScrPixel的亮度也不足以其任何一个成员原先的一半,正是这三个变量抑制了ScrPixel的亮度,使得最终混合图像不是我想象的那样。
看来唯有实践才能知道最终是什么结果.
写代码时容易犯的错误:
1. 最后一个Pass中混合纹理时三个纹理采样,Mipmap,Maxfliter及Minfliter均设置为D3DTEXF_LINER,Glow3对画面影响最严重,若果不设置为D3DTEXF_LINER,会出现马赛克 :)
2. Render to texture时一定要注意:
1 Out.texCoord.x = 0.5 * (1 + Pos.x - 1/128); 2 Out.texCoord.y = 0.5 * (1 - Pos.y - 1/128);
后边的1/128千万不要写成1.0/128.0,要不然画面会向右偏移(我用的是XP系统),这个现象目前尚未搞明白为什么 :(
//End......