因为Alpha混合不一样,d3d渲染物体到RenderTarget再渲染到Screen的过程和把物体直接渲染到Screenbuffer中并不对等。具体为什么不对等,这里说的很详细。这样的话,有些2d游戏需要利用3d渲染的能力实现换装的过程就可能产生下面的一个问题:角色的半透明披风与身体重叠区域B会呈现不正确的半透明状态,露出地表。
产生这个问题的原因就是2d游戏需要先将3d资源渲染到RenderTarget,然后再应用到已有的2d sprite渲染引擎中;因为渲染到RenderTarget时,如果按照默认的alpha混合方式,D3D会对颜色通道和alpha通道执行相同的混合策略,因此如上图,角色部分会导致B区域被写上Alpha信息,即呈半透明状态。
解决这个问题的方法是:修改披风的材质,将alpha通道的混合方式独立出来。ms的官方文档这样描述这个策略:Render Target Alpha (Direct3D 9)。
但是设置了alpha单独混合之后还不够,对于alpha通道选取怎样的混合函数则照样会影响结果是否显示正确,经过一些尝试,一个比较好的方法是这样的:
RenderState.SeparateAlphaBlendEnable = true;
RenderState.AlphaBlendEnable = true;
RenderState.SourceBlend = Blend.SourceAlpha; // source rgb * source alpha
RenderState.AlphaSourceBlend = Blend.One; // don't modify source alpha
RenderState.DestinationBlend = Blend.InverseSourceAlpha; // dest rgb * (255 - source alpha)
RenderState.AlphaDestinationBlend = Blend.InverseSourceAlpha; // dest alpha * (255 - source alpha)
RenderState.BlendFunction = BlendFunction.Add; // add source and dest results
计算结果相当于:
A_final = A_src * 1 + (1-A_src)*A_dest;
R_final = R_src*A_src + (1-A_src)*R_dest;
G_final = G_src*A_src + (1-A_src)*G_dest;
B_final = B_src*A_src + (1-A_src)*B_dest;