2010-05-18 16 views
9

J'essaie d'appliquer du brouillard de guerre sur des zones de l'écran qui ne sont pas visibles pour le lecteur. Je le fais en rendant le contenu du jeu dans un RenderTarget et le brouillard de la guerre dans un autre, puis je les fusionne avec un fichier d'effets qui prend la couleur du jeu RenderTarget et l'alpha de la brume de la guerre rend la cible. Le FOW RenderTarget est en noir lorsque le FOW apparaît et en blanc dans le cas contraire.Utiliser l'effet pour le brouillard de guerre

Cela fonctionne, mais il colore le brouillard de la guerre (les emplacements non révélés) en blanc au lieu de la couleur prévue du noir.

Avant d'appliquer l'effet, je vide le backbuffer de l'appareil en blanc. Quand j'essaie de le faire passer au noir, il n'apparaît pas du brouillard de la guerre, ce que je suppose être un produit de l'alpha mélangé avec le noir. Cela fonctionne pour toutes les autres couleurs, cependant - donnant à l'écran résultant une teinte de cette couleur.

Comment puis-je archiver un brouillard noir tout en étant capable d'effectuer un mélange alpha entre les deux cibles de rendu?

Le code de rendu pour l'application du 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(); 
    } 

Le fichier effet que je utilise pour appliquer la 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(); 
    } 
} 

Répondre

3

Je ne ai pas regardé trop profondément dans XNA et ne peut pas mettre en place pour le moment pour vérifier avec le CTP de 4.0, mais à la lecture de la documentation, il vous ressemble 'doublons. D'après ma compréhension, BlendState.AlphaBlend provoque le SpriteBatch pour mélanger chaque sprite qui est dessiné.

Selon le documentation il utilise les paramètres par défaut de

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

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

ce qui devrait avoir les éléments suivants impact:

Un: Chaque composant de la couleur est multipliée par (1, 1 , 1, 1).

InverseSourceAlpha: Chaque composant de la couleur est multipliée par l'inverse de la valeur alpha de la source. Ce peut être représenté par (1 - As, 1 - As, 1 - As, 1 - As), où As est la valeur de destination alpha .

Donc, si vous utilisez Blend.AlphaBlend vous devriez être en mesure de vider votre tampon de retour au noir, puis seulement de rendre vos sprites carte, abaissant directement l'alpha où il devrait être fanée. Cela devrait simplement faire pâlir les pixels de la carte où «couvert» par FOW, ce qui le rendrait alpha avec le noir du tampon arrière.

Si vous souhaitez adopter l'approche des shaders, vous pouvez fusionner alpha dans le shader entre deux cibles de rendu.Je suis un peu confus de votre explication sur la façon dont vous voulez vraiment mélanger. Vous dites que vous voulez mélanger alpha, mais que votre objectif de rendu de FOW est noir là où il y a du brouillard et du blanc là où il n'y en a pas. Si vous utilisez l'alpha pour contrôler le mélange, votre couleur de brouillard doit être uniforme (ou texturée selon le cas) sur l'ensemble de la cible de rendu, selon l'apparence que vous voulez. Dites que vous voulez du brouillard noir, vos couleurs doivent être (0, 0, 0) sur l'ensemble de la cible de rendu, et la valeur alpha doit changer en fonction de l'endroit où vous voulez l'afficher.

En utilisant cette approche, vous pouvez changer votre shaders à quelque chose comme ce qui suit:

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

Je n'ai pas fait shaders HLSL pendant un certain temps, mais je suis sûr que peut être écrit beaucoup plus facile. Quoi qu'il en soit, si FOW est noir (et que le tampon arrière est effacé en noir, et que vous n'empilez pas plusieurs sprites alpha-mélangés les uns sur les autres - voir la réponse de Joel), cette approche n'est pas différente map sprite basé sur s'il y a FOW ou non.

+0

Réponse très utile. J'ai eu un les concepts de l'alpha et du mélange foiré. My LightTarget RT est maintenant transparent dans les zones visibles, et complètement noir opaque partout ailleurs. Cela me permet d'utiliser une version modifiée de votre shader pour dessiner le fow. Au lieu de color.r * (1-fow.a) j'utilise fow.r * (1-fow.a). –