XNA Creators Club Online
Page 1 of 1 (7 items)
Sort Posts: Previous Next

Lights and Shadows techniques - Experts advice needed...

Last post 3/23/2009 4:27 PM by MJP. 6 replies.
  • 3/21/2009 10:51 AM

    Lights and Shadows techniques - Experts advice needed...

    Hi,
    I'm currently trying to implement multiple lights into my game, while each light can be point, spot or directional and will cast shadow and everything.

    What I'm doing now is - for each pixel I calculate the effect of each light (up to 5 lights) and add it to the pixel color. something like this:

    float4 diffuseColor = tex2D(TextureSampler, PSIn.TextureCoords);

     

    float4 lightsColor = float4(0,0,0,0);

    for(int i=0; i< xNumOfLights; i++)

        lightsColor += CalculateSingleLight(Lights[i], PSIn.WorldPosition, PSIn.Normal, diffuseColor, 0);

     

    Output.Color.rgb = lightsColor;


    But this requires the GPU to support PS 3.0.
    Another technique is to call the same Pass over and over for each light, and use additive blend.
    But this is very slow.... (but does not require PS 2.0)

    Now I read in riemers book that he does something else completly.
    he renders the scene into 3 render targets -   1. diffuse, 2. normals, 3. Depth
    and then calculate the lighting on each pixel using the normal and depth values from the render targets.

    so my question is:

    What is the fastest way?
    is riemers technique faster than the one I use? (with PS 3.0)?

    I havn't try it yet because it means I need to change my entire code... so I want to hear about it first.


    Another major consideration is - Shadows.
    Which way is the best and most efficient way to render shadows?

    On riemers books he uses shadow maps. but that's only good for spot lights because point light will need to generate at least 4 shadow maps (90 degrees projection width in each map)
    and directional lights needs to render to much of a big area each time.

    I heard that there's a way using stencils, but I'm not sure how.

    so what is the best way in your opinion??

    Thanks!

  • 3/21/2009 10:56 PM In reply to
    • (2342)
    • premium membership MVP
    • Posts 1,226

    Re: Lights and Shadows techniques - Experts advice needed...

    It sounds like you're talking about deferred rendering.  What's important to know with deferred rendering is that it's merely a different way reorganizing the lighting pipeline so that you get a different set of benefits and drawbacks.  So in other words...it's not a magic "fix" for any problem, it's a tradeoff that could make certain things perform better while also making other things perform worse.

    These are the main benefits:

    -Can simply parts of your lighting pipeline.  You rendering will (primarily) be split into two parts: rendering geometry to a G-Buffer, and then rendering your lighting pass.  Since you no longer have to manage what lighting is associated with which geometry
    -Usually you can improve batching since your G-Buffer shaders will be simpler, and you don't have lighting to worry about
    -You only apply lighting to visible pixels (if you use proper optimizations)
    -Lighting cost becomes tied to the number of pixels shaded, not to the number of meshes affected by a light source
    -Generally coherent memory access patterns, which are good for a GPU
    -Shadow maps become much easier to implement, since lighting is done in a separate pass
    -Can use "lazy shadowmap generation", which lets you re-use shadowmaps to save memory
    -No hard limit on the number of lights due to shader constants or instruction limits

    These are the main drawbacks:

    -Can't handle alpha-blending without D3D10-level techniques.  This generally means you have to a standard forward-rendering pass for alpha-blended geometry, which can somewhat cancel out the "simplified pipeline" benefits
    -Can't use multisample anti-aliasing without D3D10-level techniques.  Supersampling is a (very expensive) option.
    -Generally increases bandwidth usage across the board due to laying out the multiple G-Buffer render targets, and sampling them in the lighting pass
    -Optimization requires minimizing the amount of pixels shaded in the lighting pass, which generally requires use of the depth buffer and stencil buffer.  Unfortunately in XNA the depth buffer is cleared whenever render targets are switched (to maintain consistency with the Xbox 360), which means the depth buffer must be manually restored whenever it's needed.
    -In XNA there's no way to use the device depth buffer as a texture, which means depth has to be rendered to a standard color texture. 
    -Much harder to to multiple materials and lighting models, since you're limited to what material properties you can store in the G-Buffer.  Some engines will store a material index in the G-Buffer, and use that to branch in the lighting pixel shader or look up more material properties from a lookup texture.

    If you're trying to decide whether a deferred renderer is a good approach, you should weigh these pro's and con's in the context of the kinds of scenes you're going to be doing.  Generally a deferred shader is a big win in scenario's where you have many small lights scattered throughout the scene.  It's generally less useful for large outdoor scenes where you only have have one main light source.  If you are interested, you should check out some of these resources:

    Deferred Shading presentation by Shawn Hargreaves
    Deferred Shading presentation by Nvidia
    Deferred Shading tutorial
    Nvidia Deferred Shading tutorial
    Deferred Shading in XNA by Catalin Zima

    Keep in mind that most of these deal with "pure" deferred shading, where you lay out a G-Buffer then do a lighting pass.  There's actually many ways to mix it up...for instance in my game I do a forward lighting pass for the sun and large light sources, and then do a deferred pass for smaller point lights using just depth and normal information.  Wolfgang Engel's light prepass renderer is another interesting approach.  Or you can even just defer your shadow maps if you want. 

    As for shadow maps vs. stencil shadows...my humble opinion is that these days shadow volumes generally aren't worth it.  They're generally less flexible, and don't scale well with geometric complexity.  It's also harder to make them look as good  as shadow maps.  While it's true you have to do multiple passes if you're using a cubemap for a point light, this usually isn't too big of a deal as long as you're culling agressively.  As for directionally lights, there's some great techniques available for optimizing shadow map texel distribution.  IMO Parallel-Split Shadow Maps produce the best results.



    Matt Pettineo | DirectX/XNA MVP


    Ride into The Danger Zone | PIX With XNA Tutorial
  • 3/22/2009 1:45 PM In reply to

    Re: Lights and Shadows techniques - Experts advice needed...

    Thank you for the thorough reply!

    I tried using deferred rendering and I got lower FPS than with the PixelShader3 technique...
    probably because of the high resolution I'm using (1680x1050)
    plus using deferred lighting with normal maps slows it down alot (I need to translate each normal on each pixel to inverse tangent space).

    as for shadows I'll go with the shadow map and make a shadow map only for the sun instead of all light sources ( I noticed that oblivion also uses only one light source for shadows, and what's good enough for them is good enough for me :-)   )

    I also noticed that the XNA creatros club has a good shadow map example which uses directional lighting.

    Thanks again for your help.


  • 3/22/2009 6:18 PM In reply to

    Re: Lights and Shadows techniques - Experts advice needed...

    With deferred rendering, you render the normal to the buffer once, in world space. The transform (including the normal map) happens before you write the normal to the frame buffer. I don't see why this would be any slower than a forward renderer.
    However, the fill rate of a deferred renderer is higher than a forward renderer for the same scene. Luckily, the Xbox has very good fill performance. You still should bound your light in screen space and use scissoring to cut down on the overhead, though.

    When it comes to shadows, point lights suck, because you have to render a cube depth map if you use shadow mapping. Cube map rendering is slow. Because the Xbox has great fill rate, you may be able to use stencil shadowing. However, with stencil shadowing, you have to render a stencil pass and an accumulation pass per light; you can't bake all the lights into a single pass like with the PS 3.0 forward renderer.

    If you're targeting the PC, then the rules are somewhat different, of course -- not only because the CPU/GPU balance is different, but also because a PC game has to scale from crappy integrated graphics like the Intel GMA 950 all the way up to a 448 bit 256 shader dual-GPU monster like the GeForce GTX 295.

    Jon Watte, Direct3D MVP
    Tweets, occasionally
    kW X-port 3ds Max .X exporter
    kW Animation source code
  • 3/22/2009 8:28 PM In reply to

    Re: Lights and Shadows techniques - Experts advice needed...

    jwatte:
    With deferred rendering, you render the normal to the buffer once, in world space. The transform (including the normal map) happens before you write the normal to the frame buffer. I don't see why this would be any slower than a forward renderer.


    because when dealing with normal maps, normally you'd transform the light direction into tangent space and that's done once per vertex.
    obviously with deferred lightings you can't transform the light into tangent space... so you need to transform each normal (which means each pixel) into inverse tangent space.
    that means a matrix multiplication for each pixel which is very slow...

    jwattte:

    When it comes to shadows, point lights suck, because you have to render a cube depth map if you use shadow mapping. Cube map rendering is slow. Because the Xbox has great fill rate, you may be able to use stencil shadowing. However, with stencil shadowing, you have to render a stencil pass and an accumulation pass per light; you can't bake all the lights into a single pass like with the PS 3.0 forward renderer.


    so stencil is out of the question...
    anyway, I decided to go with one shadow map - only from the sun's directional light.
    after all I'm not trying to compete with the crytek engine...

    jwattte:

    If you're targeting the PC, then the rules are somewhat different, of course -- not only because the CPU/GPU balance is different, but also because a PC game has to scale from crappy integrated graphics like the Intel GMA 950 all the way up to a 448 bit 256 shader dual-GPU monster like the GeForce GTX 295.


    Actually I am targeting PC and I try to make it as flexible as possible, that's why I had trouble with the PS 3 forward renderer...
  • 3/23/2009 9:47 AM In reply to

    Re: Lights and Shadows techniques - Experts advice needed...

    jwatte:
    Luckily, the Xbox has very good fill performance. You still should bound your light in screen space and use scissoring to cut down on the overhead, though.
    I'm actually having fillrate problems with our renderer, partly because of the deferred rendering and partly because we do glow and distortion passes afterwards. Could you possibly elaborate those optimization suggestions you mentioned? I don't exactly understand what you mean by either, how does screen space lights help my fill rate? And what could I scissor away without it degrading the light setting?

    Regards
  • 3/23/2009 4:27 PM In reply to
    • (2342)
    • premium membership MVP
    • Posts 1,226

    Re: Lights and Shadows techniques - Experts advice needed...

    Oren-

    Just transform your tangent-space normals to world-space or view-space in your G-Buffer pixel shader.  A multiplication or two should not have any (serious) performance implications...GPU's tend to have tons of ALU math power to spare. 


    HerrUppoHopppa-

    See those presentations I linked to, they go into detail.  The idea of scissoring or light volumes is to make sure you only shade pixels that a light source could "touch" or "affect".  So for instance if you have a small point light on the left side of the screen, there's no point in running the point light pixel shader on the right side of the screen because none of those pixels will be lit by that light source.  Going further than that you can use z-buffer and stencil to reject pixels when a light source is "floating in the air", or "buried under the ground".  But like I said before, these optimizations are complicated by the fact that in XNA your depth and stencil data gets cleared upon switching RenderTargets.
    Matt Pettineo | DirectX/XNA MVP


    Ride into The Danger Zone | PIX With XNA Tutorial
Page 1 of 1 (7 items) Previous Next