XNA 4带有Alpha通道的渲染目标

3

我希望能够做一件简单的事情:将一个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通道进行计算,而不得到纹理颜色。我该怎么做?
谢谢。
1个回答

0

你说的是(我得到的只是一个纯白色的质地...)但我得到的是: 在此输入图片描述


好的,请看一下你的renderTarget宽度和高度。它是200 x 200。然后看一下你绘制纹理的位置,new Vector2(200, 200)和new Vector2(250, 250)。所以纹理被绘制在renderTarget之外,没有出现在renderTarget纹理上。请改为设置new Vector2(0, 0)和new Vector2(50, 50)。 :D - Wallstrider
1
我使用了简单的XNA 4.0,只需复制并粘贴您的代码,然后更改纹理位置即可。这就是全部。我可以分享该项目,其中包含上面的结果图像。 - Wallstrider
谢谢wallstrider,你的代码确实有效。我逐行比较了我的代码和你的代码,它们是一样的,但是我的代码却不起作用。我唯一能想到的解释是我没有使用XNA 4.0程序集,而是通过monogame使用Xna 4.0...看起来问题出在monogame上,而不是我的代码...我正在调查这个方向。(至于纹理大小和位置,这些是我发布时的错误,问题并不是出在那里。我已经在我的帖子中修复了代码) - fbf
1
请将此作为您自己问题的已接受答案发布。我刚刚花了20分钟来解决这个问题。 - James
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接