2010-05-18 3 views
9

Я пытаюсь применить туман войны к областям на экране, которые в настоящее время не видны игроку. Я делаю это, предоставляя игровое содержимое в одном 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(); 
    } 
} 

ответ

3

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

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

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

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

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

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

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

Так что, если вы используете 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 или нет.

+0

Очень полезный ответ. У меня были понятия альфы и смешивания. Мой LightTarget RT теперь прозрачен в видимых областях и полностью непрозрачен черным везде. Это позволяет мне использовать модифицированную версию вашего шейдера, чтобы нарисовать фову. Вместо color.r * (1-fow.a) Я использую fow.r * (1-fow.a). –

1

Это звучит, как вы работаете в ситуации, Shawn Hargreaves описанные в этом сообщении в блоге:
Premultiplied Alpha and Image Composition

Попробуйте переключиться на pre-multiplied alpha, так как он предлагает ests и сообщите нам об итогах :-)

Смежные вопросы