使用战争迷雾效果

发布于 2024-09-02 08:49:46 字数 1777 浏览 5 评论 0原文

我正在尝试将战争迷雾应用到屏幕上当前玩家不可见的区域。为此,我将游戏内容渲染在一个 RenderTarget 中,将战争迷雾渲染到另一个中,然后将它们与一个效果文件合并,该效果文件从游戏 RenderTarget 中获取颜色> 以及来自战争迷雾渲染目标的 alpha。 FOW RenderTarget 在 FOW 出现的地方为黑色,在不出现的地方为白色。

这确实有效,但它将战争迷雾(未揭示的位置)着色为白色,而不是预期的黑色。

在应用效果之前,我将设备的后台缓冲区清除为白色。当我尝试将其清除为黑色时,根本没有出现战争迷雾,我认为这是阿尔法与黑色混合的产物。然而,它适用于所有其他颜色 - 使生成的屏幕具有该颜色的色调。

如何在实现黑雾的同时仍然能够在两个渲染目标之间进行 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();
    }
}

I'm trying to apply fog of war to areas on the screen not currently visible to the player. I do this by rendering the game content in one RenderTarget and the the fog of war into another, and then I merge them with an effect file that takes the color from the game RenderTarget and the alpha from the fog of war render target. The FOW RenderTarget is black where the FOW appears, and white where it doesn't.

This does work, but it colors the fog of war (the unrevealed locations) white instead of the intended color of black.

Before applying the effect I clear the backbuffer of the device to white. When I try to clear it to black, non of the fog of war appears at all, which I assume is a product of alpha blending with black. It works for all other colors, however - giving the resulting screen a tint of that color.

How do I archieve a black fog while still being able to do alpha blending between the two render targets?

The rendering code for applying the 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();
    }

The effect file I'm using to apply the 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();
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

怀中猫帐中妖 2024-09-09 08:49:46

我还没有深入研究 XNA,目前无法设置它来检查 4.0 的 CTP,但从阅读文档来看,您似乎在加倍。根据我的理解,BlendState.AlphaBlend 会导致 SpriteBatch 对绘制的每个精灵进行 alpha 混合。

根据 文档 它使用默认设置,

ColorSourceBlend = Blend.One,
AlphaSourceBlend = Blend.One,

ColorDestinationBlend = Blend.InverseSourceAlpha,
AlphaDestinationBlend = Blend.InverseSourceAlpha,

其中应具有以下内容 影响

:颜色的每个分量乘以 (1, 1, 1, 1)。

InverseSourceAlpha:每个组件
颜色乘以倒数
源的 alpha 值。这
可以表示为 (1 − As, 1 − As,
1 − As, 1 − As),其中 As 是 alpha
目标值。

因此,如果您使用 Blend.AlphaBlend,您应该能够将后台缓冲区清除为黑色,然后仅渲染地图精灵,直接降低应褪色的 Alpha。这应该简单地淡化被 FOW“覆盖”的贴图像素,使其与后台缓冲区的黑色进行 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 的方法没有什么不同。根据是否有FOW来映射精灵。

I haven't looked too deeply into XNA and can't set it up at the moment to check with the CTP of 4.0, but from reading the documentation it looks like you're doubling up. From my understanding, BlendState.AlphaBlend causes the SpriteBatch to alpha blend each sprite that is drawn.

According to the documentation it uses the default settings of

ColorSourceBlend = Blend.One,
AlphaSourceBlend = Blend.One,

ColorDestinationBlend = Blend.InverseSourceAlpha,
AlphaDestinationBlend = Blend.InverseSourceAlpha,

Which should have the following impact:

One: Each component of the color is multiplied by (1, 1, 1, 1).

InverseSourceAlpha: Each component of
the color is multiplied by the inverse
of the alpha value of the source. This
can be represented as (1 − As, 1 − As,
1 − As, 1 − As), where As is the alpha
destination value.

So if you're using Blend.AlphaBlend you should be able to clear your back buffer to black and then only render your map sprites, directly lowering the alpha where it should be faded. This should simply fade the map pixels where 'covered' by FOW, causing it to alpha blend with the black of the back buffer.

If you want to take the shader approach you can alpha blend in the shader between two render targets. I'm a bit confused from your explanation on how exactly you actually want to blend. You say you want to alpha blend, but that your render target of FOW is black where there is fog and white where there isn't. If you're using alpha to control the blending, your fog colour should be uniform (or textured as appropriate) across the whole render target, as per what appearance you want. Say you want black fog, your colours should be (0, 0, 0) across the whole render target, and the alpha value should change depending on where you want to show it.

Using this approach you could change your shader to something like the following:

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);
}

I haven't done HLSL shaders for a while but I'm sure that can be written much easier. Either way, if FOW is black (and back buffer is cleared to black, and you're not stacking various alpha-blended sprites on top of each other - see Joel's answer), that approach is no different to directly setting the alpha of the map sprite based on whether there is FOW or not.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文