2
\$\begingroup\$

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(); } } 
\$\endgroup\$
7
  • 2
    \$\begingroup\$ 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. \$\endgroup\$ Commented Jul 26, 2012 at 11:13
  • \$\begingroup\$ 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. \$\endgroup\$ Commented Jul 26, 2012 at 11:22
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ Commented Jul 26, 2012 at 12:54
  • 5
    \$\begingroup\$ 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. \$\endgroup\$ Commented Jul 26, 2012 at 13:36
  • 3
    \$\begingroup\$ 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. \$\endgroup\$ Commented Jul 26, 2012 at 19:01

1 Answer 1

1
\$\begingroup\$

Do not use full screen quads for your light volumes.

A simple way is to draw a sphere for each light, in the position that the light occupies and of the same radius.

This way, only the fragments actually affected by the light will be affected and your fragment shader will not be executed for the entire screen surface.

\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.