Simple 2D LightMap Shader Not Working

Trying to do the classic gradient circle lights seen commonly back in the XNA days:

Pass 1: Render lights into a light map
Pass 2: Render Scene
Pass 3: Multiply in shader

Set up the shader as this:

#if OPENGL
	#define SV_POSITION POSITION
	#define VS_SHADERMODEL vs_3_0
	#define PS_SHADERMODEL ps_3_0
#else
	#define VS_SHADERMODEL vs_4_0_level_9_1
	#define PS_SHADERMODEL ps_4_0_level_9_1
#endif

Texture2D Texture : register(t0);
sampler TextureSampler : register(s0)
{
Texture = (Texture);
};

Texture2D LightMap;
sampler LightMapSampler 
{
	Texture = <LightMap>;
};

float4 Main(float4 position : SV_Position, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
	float4 mainColor	= tex2D(TextureSampler, texCoord);
	float4 lightColor 	= tex2D(LightMapSampler, texCoord);
	return mainColor * lightColor;
}

technique BasicColorDrawing
{
	pass P0
	{
		PixelShader = compile PS_SHADERMODEL Main();
	}
};

This results in just a black texture with no out put, the code for drawing is as below:

        // Create a Light Mask to pass to the pixel shader
        GraphicsDevice.SetRenderTarget(m_LightMap);
        GraphicsDevice.Clear(Color.Black);
        m_SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Additive);
        m_SpriteBatch.Draw(m_Light.LightCookie, new Vector2(0, 0), Color.White);
        m_SpriteBatch.Draw(m_Light.LightCookie, new Vector2(500, 0), Color.White);
        m_SpriteBatch.Draw(m_Light.LightCookie, new Vector2(500, 200), Color.White);
        m_SpriteBatch.Draw(m_Light.LightCookie, new Vector2(100, 400), Color.White);
        m_SpriteBatch.End();

        // Draw the main scene to the Render Target
        GraphicsDevice.SetRenderTarget(m_Camera.RenderTexture);
        GraphicsDevice.Clear(Color.CornflowerBlue);
        m_SpriteBatch.Begin();
        m_SpriteBatch.Draw(m_Texture, new Rectangle(0,0, m_GraphicsDevice.Viewport.Width, m_GraphicsDevice.Viewport.Height), Color.White);
        m_SpriteBatch.End();

        // Blend together
        m_LightEffect.CurrentTechnique = m_LightEffect.Techniques[0];
        m_LightEffect.Parameters["LightMap"].SetValue(m_LightMap);
        GraphicsDevice.SetRenderTarget(null);
        GraphicsDevice.Clear(Color.Black);
        m_SpriteBatch.Begin(SpriteSortMode.Immediate, null, null, null, null, m_LightEffect, null); 
        m_SpriteBatch.Draw(m_Camera.RenderTexture, Vector2.Zero, Color.White);
        m_SpriteBatch.End();

This is the LightMap Target:

And the scene target is just filled with a free brick texture for test purposes instead of my tile map:
TheScene

Thanks.

Hi,

and welcome :wink:

It can be another thing but I think you must do this with the rendertarget :

_graphicsDevice.SetRenderTarget(_renderTargetLight);
_graphicsDevice.Clear(Black);
//Draw 
_graphicsDevice.SetRenderTarget(null);

_graphicsDevice.SetRenderTarget(_renderTargetMap);
_graphicsDevice.Clear(Black);
//Draw 
_graphicsDevice.SetRenderTarget(null);

//Draw rendertarget

I think i get what you mean? the ol its bound but your trying to use it as a texture? unfortunatly doesnt seem to change much. However if instead you remove the shader and BlendMultiply with just sprite effect it works fine. But im still curious why the shader does work for others…

  GraphicsDevice.SetRenderTarget(null);
  GraphicsDevice.Clear(Color.White);
  m_SpriteBatch.Begin(SpriteSortMode.Immediate, Multiply);
  m_SpriteBatch.Draw(m_Camera.RenderTexture, Vector2.Zero, Color.White);
  m_SpriteBatch.Draw(m_LightMap, Vector2.Zero, Color.White);
  m_SpriteBatch.End();

Sorry my english is really bad :sweat_smile:

When I use shader with rendertarget I do this :

// Draw 
        GraphicsDevice.Clear(Color.Black);

        m_LightEffect.CurrentTechnique = m_LightEffect.Techniques["BasicColorDrawing"]; // I replace this
        m_LightEffect.Parameters["LightMap"].SetValue(m_LightMap);            
        m_LightEffect.CurrentTechnique.Passes[0].Apply(); // I add this
        m_SpriteBatch.Begin(SpriteSortMode.Immediate, null, null, null, null, m_LightEffect, null); 
        m_SpriteBatch.Draw(m_Camera.RenderTexture, Vector2.Zero, Color.White);
        m_SpriteBatch.End();

Same problem persists just a black output, if you set target to blue though it outputs blue. Its as though the shader doesnt actually output anything other than the backbuffers color.

I found this a few years ago, it is also possible that it is on this forum. One possible way to get nice lights without a custom shader.

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace LightTest
{
    public class Game1 : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Texture2D light, wall;
        RenderTarget2D darkness;
        BlendState blend = new BlendState();

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }


        protected override void Initialize()
        {
            graphics.PreferredBackBufferWidth = 1280;
            graphics.PreferredBackBufferHeight = 720;
            graphics.SynchronizeWithVerticalRetrace = false;
            graphics.IsFullScreen = false;
            IsFixedTimeStep = true;
            IsMouseVisible = true;
            graphics.ApplyChanges();

            darkness = new RenderTarget2D(GraphicsDevice, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight);

            blend.AlphaSourceBlend = Blend.Zero;
            blend.AlphaDestinationBlend = Blend.InverseSourceColor;
            blend.ColorSourceBlend = Blend.Zero;
            blend.ColorDestinationBlend = Blend.InverseSourceColor;

            base.Initialize();
        }


        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            light = Content.Load<Texture2D>("light");
            wall = Content.Load<Texture2D>("wall");
        }


        protected override void UnloadContent()
        {

        }


        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();

            base.Update(gameTime);
        }


        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.SetRenderTarget(darkness);

            spriteBatch.Begin(blendState: blend);
            spriteBatch.Draw(light, new Vector2(0, 0), Color.White);
            spriteBatch.Draw(light, new Vector2(100, 0), Color.White);
            spriteBatch.Draw(light, new Vector2(50, 100), Color.White);
            spriteBatch.Draw(light, new Vector2(200, 100), Color.White);
            spriteBatch.Draw(light, new Vector2(300, 300), Color.White);
            spriteBatch.Draw(light, new Rectangle(400, 0, light.Width * 2, light.Height * 2), new Rectangle(0, 0, light.Width, light.Height), Color.White);
            spriteBatch.Draw(light, new Rectangle(700, 100, light.Width * 2, light.Height * 2), new Rectangle(0, 0, light.Width, light.Height), Color.White);
            spriteBatch.End();

            GraphicsDevice.SetRenderTarget(null);

            spriteBatch.Begin();
            spriteBatch.Draw(wall, Vector2.Zero, Color.White);
            spriteBatch.Draw(darkness, Vector2.Zero, Color.White);
            spriteBatch.End();

            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Additive);
            spriteBatch.Draw(light, new Vector2(0, 0), Color.Red);
            spriteBatch.Draw(light, new Vector2(100, 0), Color.Green);
            spriteBatch.Draw(light, new Vector2(50, 100), Color.Blue);
            spriteBatch.Draw(light, new Vector2(200, 100), Color.White);
            spriteBatch.Draw(light, new Vector2(300, 300), new Color(255, 255, 255, 100));
            spriteBatch.Draw(light, new Rectangle(400, 0, light.Width * 2, light.Height * 2), new Rectangle(0, 0, light.Width, light.Height), new Color(255, 255, 255, 150));
            spriteBatch.Draw(light, new Rectangle(700, 100, light.Width * 2, light.Height * 2), new Rectangle(0, 0, light.Width, light.Height), new Color(255, 255, 50, 125));
            spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}

Its ok,

Fx file :

#if OPENGL
#define SV_POSITION POSITION
#define VS_SHADERMODEL vs_3_0
#define PS_SHADERMODEL ps_3_0
#else
#define VS_SHADERMODEL vs_4_0_level_9_1
#define PS_SHADERMODEL ps_4_0_level_9_1
#endif


sampler TextureSampler : register(s0)
{
	Texture = <TextureMap>;
};

Texture2D LightMap;
sampler LightMapSampler : register(s1)
{
	Texture = <LightMap>;
};

struct VertexShaderOutput
{
	float4 Position : SV_POSITION;
	float4 Color : COLOR0;
	float2 texCoord : TEXCOORD0;
};

float4 Main(VertexShaderOutput input) : COLOR0
{
	float4 colormap = tex2D(TextureSampler, input.texCoord);
	float4 colorlight = tex2D(LightMapSampler, input.texCoord);
	return colorlight * colormap;
}

technique BasicColorDrawing
{
	pass P0
	{
		PixelShader = compile PS_SHADERMODEL Main();
	}
};

and draw method :

// Create a Light Mask to pass to the pixel shader
            GraphicsDevice.SetRenderTarget(lightRender_);
            GraphicsDevice.Clear(Color.Black);
            spriteBatch.Begin();// SpriteSortMode.Immediate, BlendState.Additive);
            spriteBatch.Draw(lightTexture_, new Vector2(0, 0), Color.White);
            spriteBatch.Draw(lightTexture_, new Vector2(500, 0), Color.White);
            spriteBatch.Draw(lightTexture_, new Vector2(500, 200), Color.White);
            spriteBatch.Draw(lightTexture_, new Vector2(100, 400), Color.White);
            spriteBatch.End();
            GraphicsDevice.SetRenderTarget(null);
            // Draw the main scene to the Render Target
            GraphicsDevice.SetRenderTarget(mapRender_);
            GraphicsDevice.Clear(Color.Black);
            spriteBatch.Begin();
            spriteBatch.Draw(mapTexture_, new Rectangle(0, 0, 780, 580), Color.White);
            spriteBatch.End();
            GraphicsDevice.SetRenderTarget(null);

            GraphicsDevice.Clear(Color.Black);
            // Blend together
            fx.CurrentTechnique = fx.Techniques["BasicColorDrawing"];
            fx.Parameters["LightMap"].SetValue(lightRender_);
           
            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
            fx.CurrentTechnique.Passes[0].Apply();

            spriteBatch.Draw(mapRender_, Vector2.Zero, Color.White);
            spriteBatch.End();

Your Draw method works too, don’t worry :wink:

Okay so the problem with the original shader was this:

Texture2D Texture : register(t0);
sampler TextureSampler : register(s0)
{
    Texture = <Texture>;
};

It has to just be:

sampler TextureSampler : register(s0)
{
    Texture = <Texture>;
};

So for the future there are 2 different methods for achieving this effect depending on weather you want to use a shader or not:

Shader Method:

#if OPENGL
	#define SV_POSITION POSITION
	#define VS_SHADERMODEL vs_3_0
	#define PS_SHADERMODEL ps_3_0
#else
	#define VS_SHADERMODEL vs_4_0_level_9_1
	#define PS_SHADERMODEL ps_4_0_level_9_1
#endif

sampler TextureSampler : register(s0)
{
    Texture = <Texture>;
};

Texture2D LightMap;
sampler LightMapSampler : register(s1)
{
	Texture = <LightMap>;
};

struct VertexShaderOutput
{
	float4 Position : SV_POSITION;
	float4 Color : COLOR0;
	float2 texCoord : TEXCOORD0;
};

float4 Main(VertexShaderOutput input) : COLOR0
{
	float4 mainColor	= tex2D(TextureSampler, input.texCoord);
	float4 lightColor 	= tex2D(LightMapSampler, input.texCoord);
	return lightColor * mainColor;
}

technique BasicColorDrawing
{
	pass P0
	{
		PixelShader = compile PS_SHADERMODEL Main();
	}
};

Using This Draw Method:

        // Create a Light Mask to pass to the pixel shader
        GraphicsDevice.SetRenderTarget(m_LightMap);
        GraphicsDevice.Clear(Color.Black);
        m_SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Additive, null, null, null, null, m_Camera.Transform);
        for (int i = 0; i < m_Light.Count; i++)
        {
            m_Light[i].Draw(m_SpriteBatch);
        }
        m_SpriteBatch.End();

        // Draw the main scene to the Render Target
        GraphicsDevice.SetRenderTarget(m_Camera.RenderTexture);
        GraphicsDevice.Clear(Color.Black);
        m_SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, null, null, null, m_Camera.Transform);
        m_Map.Draw(m_SpriteBatch, m_Camera);
        m_SpriteBatch.End();

        // Blend together
        GraphicsDevice.SetRenderTarget(null);
        GraphicsDevice.Clear(Color.Black);
        m_LightEffect.Parameters["LightMap"].SetValue(m_LightMap);
        m_SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, null, null, null, m_LightEffect, null);
        m_SpriteBatch.Draw(m_Camera.RenderTexture, Vector2.Zero, Color.Black);
        m_SpriteBatch.End();

For the None Shader Method simply make a Multiply blend state and blend together on white target:

Blend Multiply:

   BlendState Multiply = new BlendState()
    {
        AlphaSourceBlend        = Blend.DestinationAlpha,
        AlphaDestinationBlend   = Blend.Zero,
        AlphaBlendFunction      = BlendFunction.Add,
        ColorSourceBlend        = Blend.DestinationColor,
        ColorDestinationBlend   = Blend.Zero,
        ColorBlendFunction      = BlendFunction.Add
    };

Draw Function:

        // Create a Light Mask to pass to the pixel shader
        GraphicsDevice.SetRenderTarget(m_LightMap);
        GraphicsDevice.Clear(Color.Black);
        m_SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Additive, null, null, null, null, m_Camera.Transform);
        for (int i = 0; i < m_Light.Count; i++)
        {
            m_Light[i].Draw(m_SpriteBatch);
        }
        m_SpriteBatch.End();

        // Draw the main scene to the Render Target
        GraphicsDevice.SetRenderTarget(m_Camera.RenderTexture);
        GraphicsDevice.Clear(Color.Black);
        m_SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, null, null, null, m_Camera.Transform);
        m_Map.Draw(m_SpriteBatch, m_Camera);
        m_SpriteBatch.End();

        // Blend together
        GraphicsDevice.SetRenderTarget(null);
        GraphicsDevice.Clear(Color.White);
        m_SpriteBatch.Begin(SpriteSortMode.Immediate, Multiply);
        m_SpriteBatch.Draw(m_Camera.RenderTexture, Vector2.Zero, Color.White);
        m_SpriteBatch.Draw(m_LightMap, Vector2.Zero, Color.White);
        m_SpriteBatch.End();

Thanks.