我希望能够做一件简单的事情:将一个2D纹理渲染到一个带有alpha通道混合的2D渲染目标中。
因此,我创建了我的渲染目标:
renderTarget = new RenderTarget2D(m_graphicsDevice, 200, 200);
然后我创建我的纹理:
texture = new Texture2D(_device, 1, 1, false, SurfaceFormat.Color);
Color clr = Color.Red;
// set half transparency on my texture
clr.A = 128;
Color[] bitmap = new Color[1] {clr};
texture.SetData(bitmap);
然后我将我的渲染目标清空为白色,并在渲染目标中两次绘制我的纹理,使用适当的比例和颜色和透明度通道上的乘法操作。
graphicsDevice.SetRenderTarget(renderTarget);
graphicsDevice.Clear(Color.White);
BlendState myState = new BlendState();
// multiplicative blending on color
myState.ColorSourceBlend = Blend.Zero;
myState.ColorDestinationBlend = Blend.SourceColor;
// multiplicative blending on alpha
myState.AlphaSourceBlend = Blend.Zero;
myState.AlphaDestinationBlend = Blend.SourceAlpha;
spriteBatch.Begin(SpriteSortMode.Immediate, myState);
// draw my texture twice, with an overlaping part
spriteBatch.Draw(texture, new Vector2(0, 0), null, Color.White, 0, Vector2.Zero, 100, SpriteEffects.None, 0);
spriteBatch.Draw(texture, new Vector2(50, 50), null, Color.White, 0, Vector2.Zero, 100, SpriteEffects.None, 0);
spriteBatch.End();
graphicsDevice.SetRenderTarget(null);
我在屏幕上绘制这个渲染目标,使用绿色背景和非预乘的渲染状态,以便纹理中的alpha值被应用为透明度。
graphicsDevice.Clear(Color.Green);
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied);
spriteBatch.Draw(renderTarget, Vector2.zero, Color.White);
spriteBatch.End();
结果如预期:
在渲染目标中,对于仅属于一个纹理的像素:
- 红色通道 = 纹理红色通道 (1) * 渲染目标红色通道 (1) = 1
- 绿色和蓝色通道 = 纹理通道 (0) * 渲染目标通道 = 0
- alpha通道 = 纹理alpha值 (0.5) * 渲染目标alpha值 (1) = 0.5
- 并且这个纹理绘制在绿色背景上时,由于alpha透明度设置为0.5(1/2红+1/2绿),会产生棕色。
在渲染目标中,对于重叠像素(因此上述计算应用两次)
- 红色通道 = 纹理红色通道 (1) * 纹理红色通道 (1) * 渲染目标红色通道 (1) = 1
- 绿色和蓝色通道 = 纹理通道 (0) * 纹理通道 (0) * 渲染目标通道 = 0
- alpha通道 = 纹理alpha值 (0.5) * 纹理alpha值 (0.5) * 渲染目标alpha值 (1) = 0.25
- 并且这个纹理绘制在绿色背景上时,由于alpha值为0.25(1/4红+3/4绿),会产生近乎绿色的颜色。
现在,如果我改变渲染状态,只允许应用纹理的alpha通道,而不是对颜色进行乘法:
BlendState myState = new BlendState();
// texture color is ignored, dest color remain unchanged
myState.ColorSourceBlend = Blend.Zero;
myState.ColorDestinationBlend = Blend.One;
// alpha chanel are still multiplied
myState.AlphaSourceBlend = Blend.Zero;
myState.AlphaDestinationBlend = Blend.SourceAlpha;
我需要得到的是:
在渲染目标中,对于属于一个纹理的像素:
- 红色通道 = 0 * 纹理红色通道 (1) + 1 * 渲染目标红色通道 (1) = 1 - 绿色和蓝色通道 = 0 * 纹理通道 (0) + 1 * 渲染目标通道 (1) = 1 - Alpha通道 = 纹理Alpha值 (0.5) * 渲染目标Alpha值 (1) = 0.5 - 在绿色背景上绘制这个纹理应该会产生浅绿色 (1/2白色 + 1/2绿色)
在渲染目标中,对于重叠的像素(因此应用了两次上述计算):
- 红色通道 = 1 - 绿色和蓝色通道 = 1 - Alpha通道 = 纹理Alpha值 (0.5) * 纹理Alpha值 (0.5) * 渲染目标Alpha值 (1) = 0.25 - 在绿色背景上绘制这个纹理应该会产生更浓的绿色 (0.25 * 白色 + 0.75 * 绿色)
但我得到的是一个纯白色的纹理...
为什么我的渲染目标中的Alpha混合计算在不混合颜色时会停止工作?我的目标是只对Alpha通道进行计算,而不得到纹理颜色。我该怎么做?
谢谢。