我正在尝试将战争雾应用于屏幕上目前玩家无法看到的区域。我通过将游戏内容渲染到一个RenderTarget
并将战争迷雾转换为另一个来实现这一点,然后我将它们与一个效果文件合并,该文件采用游戏RenderTarget
的颜色和来自游戏的alpha。战争迷雾渲染目标。 FOW RenderTarget
在FOW出现时为黑色,而在FOW出现时为白色。
这确实有效,但它会将战争迷雾(未显示的位置)变成白色,而不是黑色的预期颜色。
在应用效果之前,我将设备的后备缓冲区清除为白色。当我试图将它清除为黑色时,根本没有出现战争迷雾,我认为这是alpha混合黑色的产物。但它适用于所有其他颜色 - 为结果屏幕提供该颜色的色调。
如何在能够在两个渲染目标之间进行Alpha混合的同时实现黑雾?
应用FOW的渲染代码:
private RenderTarget2D mainTarget;
private RenderTarget2D lightTarget;
private void CombineRenderTargetsAndDraw()
{
batch.GraphicsDevice.SetRenderTarget(null);
batch.GraphicsDevice.Clear(Color.White);
fogOfWar.Parameters["LightsTexture"].SetValue(lightTarget);
batch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
fogOfWar.CurrentTechnique.Passes[0].Apply();
batch.Draw(
mainTarget,
new Rectangle(0, 0, batch.GraphicsDevice.PresentationParameters.BackBufferWidth, batch.GraphicsDevice.PresentationParameters.BackBufferHeight),
Color.White
);
batch.End();
}
我用来应用FOW的效果文件:
texture LightsTexture;
sampler ColorSampler : register(s0);
sampler LightsSampler = sampler_state{
Texture = <LightsTexture>;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
};
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
float2 tex = input.TexCoord;
float4 color = tex2D(ColorSampler, tex);
float4 alpha = tex2D(LightsSampler, tex);
return float4(color.r, color.g, color.b, alpha.r);
}
technique Technique1
{
pass Pass1
{
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}
答案 0 :(得分:3)
我没有深入研究XNA并且目前无法设置它来检查4.0的CTP,但是从阅读文档看起来你看起来已经翻倍了。根据我的理解,BlendState.AlphaBlend
会导致SpriteBatch
与alpha混合绘制的每个精灵。
根据documentation,它使用
的默认设置ColorSourceBlend = Blend.One,
AlphaSourceBlend = Blend.One,
ColorDestinationBlend = Blend.InverseSourceAlpha,
AlphaDestinationBlend = Blend.InverseSourceAlpha,
哪个应该有以下impact:
一个:颜色的每个分量都乘以(1,1,1,1)。
InverseSourceAlpha :每个组件 颜色乘以逆 源的alpha值。这个 可以表示为(1 - As,1 - As, 1 - As,1 - As),其中As是alpha 目的地价值。
因此,如果你正在使用Blend.AlphaBlend
,你应该能够将你的后台缓冲区清除为黑色,然后只渲染你的地图精灵,直接降低应该褪色的alpha值。这应该简单地淡化FOW“覆盖”的地图像素,使其与后面缓冲区的黑色进行alpha混合。
如果要采用着色器方法,可以在两个渲染目标之间的着色器中进行Alpha混合。我对你究竟想要如何融合的解释感到有些困惑。你说你想要alpha混合,但你的FOW渲染目标是黑色,有雾,而白色没有。如果您使用alpha来控制混合,则您的雾颜色应该在整个渲染目标上均匀(或根据需要进行纹理化),具体取决于您想要的外观。假设你想要黑雾,你的颜色应该是整个渲染目标的(0,0,0),并且alpha值应该根据你想要显示它的位置而改变。
使用此方法,您可以将着色器更改为以下内容:
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
float2 tex = input.TexCoord;
float4 color = tex2D(ColorSampler, tex);
float4 fow = tex2D(LightsSampler, tex);
// color * inverse of FOW alpha + FOW * FOW alpha
return float4(color.r * (1-fow.a) + fow.r * fow.a,
color.g * (1-fow.a) + fow.g * fow.a,
color.b * (1-fow.a) + fow.b * fow.a,
1);
}
我有一段时间没有完成HLSL着色器,但我确信可以写得更容易。无论哪种方式,如果FOW是黑色的(并且后面的缓冲区被清除为黑色,并且你没有将各种alpha混合的精灵堆叠在一起 - 请参阅Joel的答案),这种方法与直接设置alpha的alpha无异。根据是否有FOW来映射精灵。
答案 1 :(得分:1)
听起来你正在遇到Shawn Hargreaves在这篇博文中描述的情况:
Premultiplied Alpha and Image Composition
尝试按照他的建议切换到pre-multiplied alpha并让我们知道结果: - )