This content may move. Please update your bookmark to point to http://vdir.us/go/2d-fog-of-war
This tutorial covers a basic way of implementing two dimensional fog of war for a game in XNA and assumes you (the reader) has basic knowledge of C# and the XNA Framework. To get things started, create an empty Windows game project. Two textures will be needed: one for the Light and one for the Background. After adding these to the Content Project, go ahead and add the following members to the game class.
Texture2D lightTexture;
Texture2D backgroundTexture;
RenderTarget2D lightTarget;
RenderTarget2D mainTarget;
Effect basicFogOfWarEffect;
While the use of the texture fields is obvious, the use of the render targets may not. The concept behind this fog of war implementation is to draw the light texture to the lightTarget render target and then use the produced texture as the alpha channel for the texture produced from the mainTarget render target.
The next task is to load up the textures and create the render targets. Note: If you have issues with the render targets, you may have to change the create statement for your GPU. A better render target creation method will be added to this article at a later date.
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
lightTexture = Content.Load("Light");
backgroundTexture = Content.Load("Background");
basicFogOfWarEffect = Content.Load("Effects/BasicFogOfWar");
mainTarget = CreateRenderTarget();
lightTarget = CreateRenderTarget();
base.LoadContent();
}
private RenderTarget2D CreateRenderTarget()
{
return new RenderTarget2D(GraphicsDevice, GraphicsDevice.PresentationParameters.BackBufferWidth, GraphicsDevice.PresentationParameters.BackBufferHeight, 1, SurfaceFormat.Color);
}
Finally the drawing can begin. The process is incredibly simple and straight forward: draw the game, draw the lights, combine the two and draw to the screen. First the "game" is drawn to the mainTarget render target.
private void DrawMain(GameTime gameTime)
{
GraphicsDevice.SetRenderTarget(0, mainTarget);
GraphicsDevice.Clear(Color.Black);
// Draw the background
spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
spriteBatch.Draw(
backgroundTexture,
new Rectangle(0, 0, GraphicsDevice.PresentationParameters.BackBufferWidth, GraphicsDevice.PresentationParameters.BackBufferHeight),
Color.White
);
spriteBatch.End();
base.Draw(gameTime);
GraphicsDevice.SetRenderTarget(0, null);
}
Step two is to draw the lights. For now drawing based on where the mouse will do nicely for a test.
private void DrawLights(GameTime gameTime)
{
GraphicsDevice.SetRenderTarget(0, lightTarget);
GraphicsDevice.Clear(Color.Black);
MouseState mouseState = Mouse.GetState();
spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
spriteBatch.Draw(
lightTexture,
new Vector2(mouseState.X, mouseState.Y),
null,
Color.White,
0f,
new Vector2(16, 16),
Vector2.One * 16,
SpriteEffects.None,
1.0f
);
spriteBatch.End();
GraphicsDevice.SetRenderTarget(0, null);
}
And finally these methods are put together and the final is drawn with the effect.
protected override void Draw(GameTime gameTime)
{
DrawMain(gameTime);
DrawLights(gameTime);
GraphicsDevice.Clear(Color.Black);
Texture2D mainTex = mainTarget.GetTexture();
Texture2D lightTex = lightTarget.GetTexture();
basicFogOfWarEffect.Parameters["LightsTexture"].SetValue(lightTex);
spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
basicFogOfWarEffect.Begin();
basicFogOfWarEffect.CurrentTechnique.Passes[0].Begin();
spriteBatch.Draw(
mainTex,
new Rectangle(0, 0, GraphicsDevice.PresentationParameters.BackBufferWidth, GraphicsDevice.PresentationParameters.BackBufferHeight),
Color.White
);
spriteBatch.End();
basicFogOfWarEffect.CurrentTechnique.Passes[0].End();
basicFogOfWarEffect.End();
}
The effect itself is incredibly simple. Combine the two textures but use a channel from the “light” texture as the alpha for the color (screen facing) texture.
texture LightsTexture;
sampler ColorSampler : register(s0);
sampler LightsSampler = sampler_state{
Texture = ;
};
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();
}
}
Download: Fog Of War Sample (968)

Great approach, however, the fog turns out white instead of black when implementing the above in XNA 4.0 (possibly also in 3.1)
If you want to get this to work in XNA 4.0
in the shader.fx file change
return float4(color.r, color.g, color.b, alpha.r);
to
return color * alpha;