Использование эффекта для тумана войны - PullRequest
9 голосов
/ 18 мая 2010

Я пытаюсь применить туман войны к областям на экране, которые в данный момент не видны игроку. Я делаю это, визуализируя игровой контент в одном RenderTarget, а туман войны - в другом, а затем объединяю их с файлом эффекта, который берет цвет из игры RenderTarget, и альфа из тумана войны рендеринга. цель. FOW RenderTarget черный там, где появляется FOW, и белый там, где его нет.

Это работает, но окрашивает туман войны (нераскрытые локации) в белый цвет вместо намеченного черного.

Перед применением эффекта я очищаю буфер устройства до белого. Когда я пытаюсь очистить его от черного, вообще не появляется туман войны, который, я полагаю, является продуктом альфа-смешения с черным. Тем не менее, он работает для всех остальных цветов - придает полученному экрану оттенок этого цвета.

Как мне заархивировать черный туман, в то же время сохраняя возможность альфа-смешивания между двумя целями рендера?

Код рендеринга для применения 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();
    }
}

Ответы [ 2 ]

3 голосов
/ 18 мая 2010

Я не слишком подробно изучил XNA и не могу настроить его сейчас, чтобы проверить его с CTP 4.0, но после прочтения документации кажется, что вы удвоились. Насколько я понимаю, BlendState.AlphaBlend вызывает альфа-смешение SpriteBatch каждого нарисованного спрайта.

Согласно документации он использует настройки по умолчанию

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

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

Который должен иметь следующий удар :

Один : каждый компонент цвета умножается на (1, 1, 1, 1).

InverseSourceAlpha : каждый компонент цвет умножается на обратный альфа-значения источника. это может быть представлен как (1 - As, 1 - As, 1 - As, 1 - As), где As - альфа целевое значение.

Так что, если вы используете Blend.AlphaBlend, вы сможете очистить свой задний буфер до черного и затем рендерить только спрайты карты, непосредственно понижая альфу там, где она должна исчезать. Это должно просто затушевывать пиксели карты, где они «покрыты» FOW, в результате чего альфа-канал смешивается с черным заднего буфера.

Если вы хотите использовать шейдерный подход, вы можете смешать альфа в шейдере между двумя целями рендеринга. Я немного запутался в твоих объяснениях, как именно ты на самом деле хочешь смешаться. Вы говорите, что хотите альфа-смешение, но ваша цель рендеринга FOW - черная там, где туман, и белая там, где ее нет. Если вы используете альфа-канал для управления смешиванием, цвет тумана должен быть равномерным (или соответствующим образом текстурированным) по всей цели рендеринга в соответствии с тем, какой внешний вид вы хотите. Скажем, вы хотите черный туман, ваши цвета должны быть (0, 0, 0) по всей цели рендеринга, и значение альфа должно меняться в зависимости от того, где вы хотите его показать.

Используя этот подход, вы можете изменить свой шейдер на что-то вроде следующего:

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 черный (а задний буфер очищен до черного, и вы не накладываете различные альфа-смешанные спрайты друг на друга - см. Ответ Джоэла), этот подход не отличается от прямой установки альфа спрайт карты, основанный на том, есть ли FOW или нет.

1 голос
/ 18 мая 2010

Похоже, что вы столкнулись с ситуацией, описанной Шоном Харгривсом в этом сообщении в блоге:
Предварительно умноженная альфа и композиция изображения

Попробуйте переключиться на предварительно умноженную альфу , как он предлагает, и сообщите нам результат: -)

...