Sign in to follow this  
FantasyVII

[XNA/MonoGame] Multipass point and ambient light help

Recommended Posts

Hello all,

 

I have a texture where I first add ambient light to it in one pass and then add point light in another pass. It works great on a single texture, but I want to draw more than one texture. So I thought I would use a RenderTarget to draw everything on it and then add ambient light to it in one pass and then add a point light in another pass. Problem is I don't know how to do that. Can anyone help me please?

 

Here is my code so far.

class Light
    {
        public Vector2 Position;
        public Vector4 Color;
        public float Intensity;
        public float Radius;

        public Light(Vector2 Position, Vector4 Color, float Intensity, float Radius)
        {
            this.Position = Position;
            this.Color = Color;
            this.Intensity = Intensity;
            this.Radius = Radius;
        }
    }

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

        Texture2D Texture;
        Vector2 Position;

        Effect effect;

        List<Light> Lights = new List<Light>();

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

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

            this.IsFixedTimeStep = false;

            base.Initialize();
        }

        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            Texture = Content.Load<Texture2D>("world");
            effect = Content.Load<Effect>("LightEffect");

            Position = Vector2.Zero;

            effect.Parameters["ScreenWidth"].SetValue((float)graphics.GraphicsDevice.Viewport.Width);
            effect.Parameters["ScreenHeight"].SetValue((float)graphics.GraphicsDevice.Viewport.Height);

            effect.Parameters["AmbientColor"].SetValue(new Vector4(1, 1, 1, 1));
            effect.Parameters["AmbientIntensity"].SetValue(0.3f);

            Lights.Add(new Light(new Vector2(170, 250), new Vector4(1, 0, 0, 1), 1.5f, 25f));
            Lights.Add(new Light(new Vector2(840, 250), new Vector4(0, 0, 1, 1), 1.5f, 25f));
            Lights.Add(new Light(new Vector2(450, 250), new Vector4(0, 1, 0, 1), 1.5f, 25f));
            Lights.Add(new Light(new Vector2(100, 100), new Vector4(0, 1, 0, 1), 1.5f, 25f));
            Lights.Add(new Light(new Vector2(200, 200), new Vector4(0, 1, 0, 1), 1.5f, 25f));
        }

        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        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.Clear(Color.Black);

            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
            effect.CurrentTechnique.Passes["AmbientLightPass"].Apply();
            spriteBatch.Draw(Texture, Position, Color.White);
            spriteBatch.End();

            for (int i = 0; i < Lights.Count; i++)
            {
                effect.Parameters["LightPosition"].SetValue(Lights[i].Position);
                effect.Parameters["LightColor"].SetValue(Lights[i].Color);
                effect.Parameters["LightIntensity"].SetValue(Lights[i].Intensity);
                effect.Parameters["LightRadius"].SetValue(Lights[i].Radius);

                spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Additive);
                effect.CurrentTechnique.Passes["PointLightPass"].Apply();
                spriteBatch.Draw(Texture, Vector2.Zero, Color.White);
                spriteBatch.End();
            }

            base.Draw(gameTime);
        }
    }

and this is my shader code:-

float ScreenWidth;
float ScreenHeight;

float AmbientIntensity;
float4 AmbientColor;

float4 LightPosition;
float4 LightColor;
float LightIntensity;
float LightRadius;

sampler _sampler;

float4 CalculateAmbientLight(float4 position : SV_Position, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
	float4 TextureMap = tex2D(_sampler, texCoord);

	return TextureMap * AmbientColor * AmbientIntensity;
}

float4 CalculatePointLight(float4 position : SV_Position, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
	float4 TextureMap = tex2D(_sampler, texCoord);

	float2 PixelPosition = float2(ScreenWidth * texCoord.x, ScreenHeight * texCoord.y);

	float2 Direction = LightPosition - PixelPosition;
	float Distance = saturate(1 / length(Direction) * LightRadius);

	return TextureMap * Distance * LightColor * LightIntensity;
}

technique Technique1
{
	pass AmbientLightPass
	{
		PixelShader = compile ps_4_0 CalculateAmbientLight();
	}
	pass PointLightPass
    {
		PixelShader = compile ps_4_0 CalculatePointLight();
    }
}

[Update]

I tried making a RenderTarget and drawing everything on it and apply only the ambient light to it. then take the render target and only apply the point light to it. The problem now is that the screen is way too dark. and when I try to increase the ambient light the point light intensity get increased instead. I don't what I'm doing wrong.

#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.GamerServices;
#endregion

namespace AndGodSaidLetThereBeLight
{
    class Light
    {
        public Vector2 Position;
        public Vector4 Color;
        public float Intensity;
        public float Radius;

        public Light(Vector2 Position, Vector4 Color, float Intensity, float Radius)
        {
            this.Position = Position;
            this.Color = Color;
            this.Intensity = Intensity;
            this.Radius = Radius;
        }
    }

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

        Texture2D Texture1, Texture2, Texture3, Texture4;
        Vector2 Position1, Position2, Position3, Position4;

        Effect effect;
        RenderTarget2D renderTarget;

        List<Light> Lights = new List<Light>();

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

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

            this.IsFixedTimeStep = false;

            base.Initialize();
        }

        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            Texture1 = Content.Load<Texture2D>("a");
            Texture2 = Content.Load<Texture2D>("b");
            Texture3 = Content.Load<Texture2D>("c");
            Texture4 = Content.Load<Texture2D>("d");

            Position1 = new Vector2(100, 100);
            Position2 = new Vector2(200, 100);
            Position3 = new Vector2(300, 100);
            Position4 = new Vector2(400, 100);

            effect = Content.Load<Effect>("LightEffect");

            effect.Parameters["ScreenWidth"].SetValue((float)graphics.GraphicsDevice.Viewport.Width);
            effect.Parameters["ScreenHeight"].SetValue((float)graphics.GraphicsDevice.Viewport.Height);

            effect.Parameters["AmbientColor"].SetValue(new Vector4(1, 1, 1, 1));
            effect.Parameters["AmbientIntensity"].SetValue(.6f);

            effect.Parameters["RenderTarget"].SetValue(renderTarget);

            PresentationParameters pp = graphics.GraphicsDevice.PresentationParameters;
            renderTarget = new RenderTarget2D(graphics.GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, true, graphics.GraphicsDevice.DisplayMode.Format, DepthFormat.Depth24);

            Lights.Add(new Light(new Vector2(170, 250), new Vector4(1, 0, 0, 1), 1.5f, 25f));
            Lights.Add(new Light(new Vector2(840, 250), new Vector4(0, 0, 1, 1), 1.5f, 25f));
            Lights.Add(new Light(new Vector2(450, 250), new Vector4(0, 1, 0, 1), 1.5f, 25f));
            Lights.Add(new Light(new Vector2(100, 100), new Vector4(0, 1, 0, 1), 1.5f, 25f));
            Lights.Add(new Light(new Vector2(200, 200), new Vector4(0, 1, 0, 1), 1.5f, 25f));
        }

        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

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

            base.Update(gameTime);
        }

        void Render()
        {
            graphics.GraphicsDevice.SetRenderTarget(renderTarget);
            graphics.GraphicsDevice.Clear(Color.Transparent);

            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
            effect.CurrentTechnique.Passes["AmbientLightPass"].Apply();
            spriteBatch.Draw(Texture1, Position1, Color.White);
            spriteBatch.Draw(Texture2, Position2, Color.White);
            spriteBatch.Draw(Texture3, Position3, Color.White);
            spriteBatch.Draw(Texture4, Position4, Color.White);
            spriteBatch.End();

            graphics.GraphicsDevice.SetRenderTarget(null);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Transparent);

            Render();

            for (int i = 0; i < Lights.Count; i++)
            {
                effect.Parameters["LightPosition"].SetValue(Lights[i].Position);
                effect.Parameters["LightColor"].SetValue(Lights[i].Color);
                effect.Parameters["LightIntensity"].SetValue(Lights[i].Intensity);
                effect.Parameters["LightRadius"].SetValue(Lights[i].Radius);

                spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Additive);
                effect.CurrentTechnique.Passes["PointLightPass"].Apply();
                spriteBatch.Draw(renderTarget, Vector2.Zero, Color.White);
                spriteBatch.End();
            }

            base.Draw(gameTime);
        }
    }
}

Shader code:-

float ScreenWidth;
float ScreenHeight;

float AmbientIntensity;
float4 AmbientColor;

float4 LightPosition;
float4 LightColor;
float LightIntensity;
float LightRadius;

sampler OriginalTexture;

texture  RenderTarget;
sampler ColorTexture = sampler_state
{
	Texture = <RenderTarget>;
};

float4 CalculateAmbientLight(float4 position : SV_Position, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
	float4 TextureMap = tex2D(OriginalTexture, texCoord);

	return TextureMap * AmbientColor * AmbientIntensity;
}

float4 CalculatePointLight(float4 position : SV_Position, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
	float4 TextureMap = tex2D(ColorTexture, texCoord);

	float2 PixelPosition = float2(ScreenWidth * texCoord.x, ScreenHeight * texCoord.y);

	float2 Direction = LightPosition - PixelPosition;
	float Distance = saturate(1 / length(Direction) * LightRadius);

	return TextureMap * Distance * LightColor * LightIntensity;
}

technique Technique1
{
	pass AmbientLightPass
	{
		PixelShader = compile ps_4_0 CalculateAmbientLight();
	}
	pass PointLightPass
    {
		PixelShader = compile ps_4_0 CalculatePointLight();
    }
}
Edited by FantasyVII

Share this post


Link to post
Share on other sites

Ok I think I've solved it. Here is my code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AndGodSaidLetThereBeLight
{
    #region Using Statements
    using System;
    using System.Collections.Generic;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Content;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;
    using Microsoft.Xna.Framework.Storage;
    using Microsoft.Xna.Framework.GamerServices;
    #endregion

    namespace AndGodSaidLetThereBeLight
    {
        class Light
        {
            public Vector2 Position;
            public Vector4 Color;
            public float Intensity;
            public float Radius;

            public Light(Vector2 Position, Vector4 Color, float Intensity, float Radius)
            {
                this.Position = Position;
                this.Color = Color;
                this.Intensity = Intensity;
                this.Radius = Radius;
            }
        }

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

            Texture2D Texture1, Texture2, Texture3, Texture4;
            Vector2 Position1, Position2, Position3, Position4;

            Effect effect;
            RenderTarget2D renderTarget;

            List<Light> Lights = new List<Light>();

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

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

                this.IsFixedTimeStep = false;

                base.Initialize();
            }

            protected override void LoadContent()
            {
                // Create a new SpriteBatch, which can be used to draw textures.
                spriteBatch = new SpriteBatch(GraphicsDevice);

                Texture1 = Content.Load<Texture2D>("a");
                Texture2 = Content.Load<Texture2D>("b");
                Texture3 = Content.Load<Texture2D>("c");
                Texture4 = Content.Load<Texture2D>("d");

                Position1 = new Vector2(100, 100);
                Position2 = new Vector2(200, 100);
                Position3 = new Vector2(300, 100);
                Position4 = new Vector2(400, 100);

                effect = Content.Load<Effect>("LightEffect");

                effect.Parameters["ScreenWidth"].SetValue((float)graphics.GraphicsDevice.Viewport.Width);
                effect.Parameters["ScreenHeight"].SetValue((float)graphics.GraphicsDevice.Viewport.Height);

                effect.Parameters["AmbientColor"].SetValue(new Vector4(1, 1, 1, 1));
                effect.Parameters["AmbientIntensity"].SetValue(.6f);

                PresentationParameters pp = graphics.GraphicsDevice.PresentationParameters;
                renderTarget = new RenderTarget2D(graphics.GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, true, graphics.GraphicsDevice.DisplayMode.Format, DepthFormat.Depth24);

                Lights.Add(new Light(new Vector2(170, 250), new Vector4(1, 0, 0, 1), 1.5f, 25f));
                Lights.Add(new Light(new Vector2(840, 250), new Vector4(0, 0, 1, 1), 1.5f, 25f));
                Lights.Add(new Light(new Vector2(450, 250), new Vector4(0, 1, 0, 1), 1.5f, 25f));
                Lights.Add(new Light(new Vector2(100, 100), new Vector4(0, 1, 0, 1), 1.5f, 25f));
                Lights.Add(new Light(new Vector2(200, 200), new Vector4(0, 1, 0, 1), 1.5f, 25f));
            }

            protected override void UnloadContent()
            {
                // TODO: Unload any non ContentManager content here
            }

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

                base.Update(gameTime);
            }

            void Render()
            {
                graphics.GraphicsDevice.SetRenderTarget(renderTarget);
                graphics.GraphicsDevice.Clear(Color.Transparent);

                spriteBatch.Begin();
                spriteBatch.Draw(Texture1, Position1, Color.White);
                spriteBatch.Draw(Texture2, Position2, Color.White);
                spriteBatch.Draw(Texture3, Position3, Color.White);
                spriteBatch.Draw(Texture4, Position4, Color.White);
                spriteBatch.End();

                graphics.GraphicsDevice.SetRenderTarget(null);
            }

            protected override void Draw(GameTime gameTime)
            {
                GraphicsDevice.Clear(Color.Transparent);

                Render();

                spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Additive);
                effect.CurrentTechnique.Passes["AmbientLightPass"].Apply();
                spriteBatch.Draw(renderTarget, Vector2.Zero, Color.White);
                spriteBatch.End();

                for (int i = 0; i < Lights.Count; i++)
                {
                    effect.Parameters["LightPosition"].SetValue(Lights[i].Position);
                    effect.Parameters["LightColor"].SetValue(Lights[i].Color);
                    effect.Parameters["LightIntensity"].SetValue(Lights[i].Intensity);
                    effect.Parameters["LightRadius"].SetValue(Lights[i].Radius);

                    spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Additive);
                    effect.CurrentTechnique.Passes["PointLightPass"].Apply();
                    spriteBatch.Draw(renderTarget, Vector2.Zero, Color.White);
                    spriteBatch.End();
                }

                base.Draw(gameTime);
            }
        }
    }
}

Shader:-

float ScreenWidth;
float ScreenHeight;

float AmbientIntensity;
float4 AmbientColor;

float4 LightPosition;
float4 LightColor;
float LightIntensity;
float LightRadius;

sampler _Sampler;

float4 CalculateAmbientLight(float4 position : SV_Position, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
	float4 TextureMap = tex2D(_Sampler, texCoord);

	return TextureMap * AmbientColor * AmbientIntensity;
}

float4 CalculatePointLight(float4 position : SV_Position, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
	float4 TextureMap = tex2D(_Sampler, texCoord);

	float2 PixelPosition = float2(ScreenWidth * texCoord.x, ScreenHeight * texCoord.y);

	float2 Direction = LightPosition - PixelPosition;
	float Distance = saturate(1 / length(Direction) * LightRadius);

	return TextureMap * Distance * LightColor * LightIntensity;
}

technique Technique1
{
	pass AmbientLightPass
	{
		PixelShader = compile ps_4_0 CalculateAmbientLight();
	}
	pass PointLightPass
    {
		PixelShader = compile ps_4_0 CalculatePointLight();
    }
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this