2010-05-18 10 views
9

Estoy tratando de aplicar fog of war a las áreas en la pantalla que el jugador no puede ver actualmente. Lo hago presentando el contenido del juego en un RenderTarget y la niebla de la guerra en otro, y luego los fusiono con un archivo de efectos que toma el color del juego RenderTarget y el alfa del objetivo de renderizado fog of war. El FOW RenderTarget es negro donde aparece el FOW y blanco donde no aparece.Uso de Effect For Fog of War

Esto funciona, pero colorea la niebla de guerra (las ubicaciones no reveladas) de color blanco en lugar del color deseado de negro.

Antes de aplicar el efecto borro el backbuffer del dispositivo a blanco. Cuando trato de borrarlo a negro, no aparece nada de la niebla de la guerra, que supongo que es un producto de mezcla alfa con negro. Sin embargo, funciona para todos los demás colores, dando a la pantalla resultante una tonalidad de ese color.

¿Cómo puedo crear una niebla negra mientras sigo siendo capaz de hacer mezclas alfa entre los dos objetivos de renderizado?

El código de representación para la aplicación de la 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(); 
    } 

El archivo de efectos que estoy usando para aplicar el 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(); 
    } 
} 

Respuesta

3

No he examinado demasiado profundamente en XNA y no puedo configurarlo en este momento para consultar con el CTP de 4.0, pero al leer la documentación parece que Doblar. Desde mi entendimiento, BlendState.AlphaBlend hace que el SpriteBatch mezcle alfa cada sprite que se dibuja.

De acuerdo con la documentation se utiliza la configuración predeterminada de

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

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

que debería tener el siguiente impact:

Una: Cada componente del color se multiplica por (1, 1 , 1, 1).

InverseSourceAlpha: Cada componente de el color se multiplica por el inverso del valor alfa de la fuente. Este se puede representar como (1 - As, 1 - As, 1 - As, 1 - As), donde As es el valor de destino alfa .

Así que si usted está utilizando Blend.AlphaBlend usted debe ser capaz de limpiar el búfer de nuevo a negro y entonces sólo hacer que sus sprites mapa, bajando directamente a la alfa donde debe ser desvaneció. Esto simplemente debería desvanecer los píxeles del mapa donde está 'cubierto' por FOW, causando que se mezcle alfa con el negro del buffer posterior.

Si desea tomar el enfoque de sombreado, puede combinar alfa en el sombreado entre dos objetivos de renderizado.Estoy un poco confundido con tu explicación sobre cómo exactamente quieres mezclar. Dices que quieres combinar alfa, pero que tu objetivo de render de FOW es negro donde hay niebla y blanco donde no lo hay. Si usa alfa para controlar la mezcla, su color de niebla debe ser uniforme (o con textura, según corresponda) en todo el objetivo de renderizado, según la apariencia que desee. Digamos que quieres niebla negra, tus colores deberían ser (0, 0, 0) en todo el objetivo de renderizado, y el valor alfa debería cambiar dependiendo de dónde quieras mostrarlo.

uso de este enfoque podría cambiar su shader a algo como lo siguiente:

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

no he hecho shaders HLSL por un tiempo, pero estoy seguro de que se puede escribir mucho más fácil. De cualquier manera, si FOW es negro (y el buffer posterior se borra a negro, y no está apilando varios sprites mezclados alfa uno encima del otro - vea la respuesta de Joel), ese enfoque no es diferente de establecer directamente el alfa del mapa de sprites según si hay FOW o no.

+0

Muy útil respuesta. Tenía los conceptos de alfa y mezcla mal. Mi LightTarget RT ahora es transparente en las áreas visibles y totalmente negro opaco en todos lados. Eso me permite usar una versión modificada de tu sombreador para dibujar el fow. En lugar de color.r * (1-fow.a) estoy usando fow.r * (1-fow.a). –