Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I've implemented deferred lighting and I tried to put about 20-26 lights on the viewable space of my map, and it brings down the FPS from 61 to 28-31. It also makes my VGA temperature to go from 68°C to 72-73°C.

I feel this a bit weird, because it's just 2D, and I don't think my implementation should be so expensive as to halve my FPS. Is there a problem with my code and how I've implemented it? Or is there any other method for good lighting which costs much less then this?

My code is:

 Texture_Lights = RenderTargetBase.GetTexture();
 for (int i = 0; i < LightRef.Count; i++)
            {


                //Draw lights
                for (int techniqueindex = 0; techniqueindex < LightRef[i].Parent.effect.Techniques.Count; techniqueindex++)
                {
                    LightRef[i].Parent.effect.CurrentTechnique = LightRef[i].Parent.effect.Techniques[techniqueindex];

                    LightRef[i].Parent.effect.Parameters["time"].SetValue(((float)timer.Elapsed.TotalSeconds) * 0.0000158f);
                    LightRef[i].Parent.effect.Parameters["GameTime"].SetValue(timer.Elapsed.Seconds);
                    LightRef[i].Parent.effect.Parameters["lightPosition"].SetValue(
                        new Vector3(
                            (LightRef[i].Position.X-CameraX)/(1.0f/ZoomFloat), 
                            (LightRef[i].Position.Y-CameraY)/(1.0f/ZoomFloat),
                            0
                            ));


                   LightRef[i].Parent.effect.Parameters["screenWidth"].SetValue(this.Width);
                   LightRef[i].Parent.effect.Parameters["screenHeight"].SetValue(this.Height);



                    for (int cx = 0; cx < LightRef[i].Parent.SelfTextures.Count; cx++)
                    {
                        LightRef[i].Parent.effect.Parameters[LightRef[i].Parent.SelfTextures[cx]].SetValue(RenderTargetBase.GetTexture());
                    }




                    foreach (EffectPass pass in LightRef[i].Parent.effect.CurrentTechnique.Passes)
                    {


                        GraphicsDevice.SetRenderTarget(0, RenderTargetLights);
                        GraphicsDevice.Clear(ClearColor);

                        spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None);
                        LightRef[i].Parent.effect.Begin();
                        LightRef[i].Parent.effect.GraphicsDevice.RenderState.AlphaBlendEnable = true;
                        pass.Begin();

                        spriteBatch.Draw(
                         Texture_Lights,
                         new Vector2(0,0),
                        new Rectangle(0, 0, Texture_Lights.Width, Texture_Lights.Height),
                        Color.White,
                        0,
                        new Vector2(0, 0),
                        1.0f,
                        SpriteEffects.None,
                        0);

                        spriteBatch.End();
                        pass.End();
                        LightRef[i].Parent.effect.End();

                        GraphicsDevice.SetRenderTarget(0, null);
                        GraphicsDevice.Clear(ClearColor);

                        Texture_Lights = RenderTargetLights.GetTexture();
                    }




                }






            }




            GraphicsDevice.SetRenderTarget(0, null);
            GraphicsDevice.Clear(ClearColor);

            //Draw the Lightings #2
            if (Texture_Lights != null)
            {
                spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None);

                spriteBatch.Draw(
                 Texture_Lights,
                 new Vector2(0, 0),
                new Rectangle(0, 0, Texture_Lights.Width, Texture_Lights.Height),
                Color.White,
                0,
                new Vector2(0, 0),
                this.ZoomFloat,
                SpriteEffects.None,
                0);

                spriteBatch.End();
            }

And my shader:

float GameTime;
float time;

texture2D colortexture;
texture2D normaltexture;

float ambient = 1.00;
float4 ambientColor = (1, 1, 1, 1);

float3 lightPosition = (230,230,0);
float4 lightColor = (120,120,120,120);
float lightPower = 0.27;

float screenWidth = 1000;
float screenHeight = 600;

sampler ColorMap = sampler_state
{
 Texture = <colortexture>;
};

sampler NormalMap = sampler_state
{
 Texture = <normaltexture>;
};



float4 DeferredNormalPS(float2 texCoords : TEXCOORD0) : COLOR
{
 float4 base = tex2D(ColorMap, texCoords);
 float3 normal = tex2D(NormalMap, texCoords);

 float3 pixelPosition = float3(screenWidth * texCoords.x, screenHeight * texCoords.y,0);

 float3 direction = lightPosition - pixelPosition;
 float distance = 1 / length(lightPosition - pixelPosition) * lightPower;
 float amount = max(dot(base + normal, normalize(distance)), 0);
 lightColor *= lightPower;

 float4 finalColor = (base * ambientColor * ambient) +
 (base * distance * amount * lightColor * ambient);

finalColor.a = base.a;

 return finalColor;
}


technique Deferred
{
 pass Pass1
 {
 PixelShader = compile ps_3_0 DeferredNormalPS();
 }
}
share|improve this question
1  
You wouldn't say "...it's just 2D", if you realized that this shader uses 3D coordinates. Deferred lighting is a 3D shading technique. Multipass deferred lighting is quite taxing on the hardware. Did you try increasing the number of lights incrementally? If you notice a large gap in performance between two increments, then there's definitely something wrong. –  Marton Jul 26 '12 at 11:13
    
Hmmm then I should use something other for lighting? I saw a few lighting solutions but I don't really know which one would be better the Deferred lighting. –  user1461097 Jul 26 '12 at 11:22
1  
The problem with deferred shading is that the base cost is quite expensive, the upside is that it scales well. Also the reason why it only became popular the last few years. –  Mr. Beast Jul 26 '12 at 12:54
5  
One of the ideas of deferred lighting is that you draw shapes for lights (i.e. a sphere for a point light) so that the pixel shader will only be run on the pixels affected by the light. All your lights seem to be represented by fullscreen quads though, while your shader looks like a point light one. So you are basically running your lighting shader on all pixels 26 times. Since you are already using a point light shader, maybe try to use circles/spheres for the light shape as well. –  melak47 Jul 26 '12 at 13:36
1  
Deferred rendering is not a magic salve that you can rub onto anything that makes it faster. It's only faster compared to the alternatives, and even then, only in specific circumstances. If you're just rendering a 2D tilemap, deferred rendering will be no faster than forward rendering, if not slower. Also, you only seem to be processing a single light per pass; there's no reason you can't have shaders that process 5 or 10 lights at once. –  Nicol Bolas Jul 26 '12 at 19:01
show 2 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.