Roy Triesscheijn’s Weblog

My programming world

Deferred Rendering in XNA4.0 Source Code

Posted by Roy Triesscheijn on December 28th, 2010

Lately I’ve been very interested in ‘the 3D stuff’. And because of this I’ve been reading into Deferred Rendering.

Catalin Zima explaind deferred rendering very nicely, by comparing it to traditional rendering methods:

In the Single-Pass lighting method, each object is rendered, and all lights affecting that object are computer in one shader. [snip]. Since everything is done in a single shader, which has a limited instruction count, this technique is only suitable for a small number of lights [snip]. In some games, which only need a small number of lights, such as an outdoor daytime environment, this may prove to be a good choice. The disadvantages of this technique are the small number of lights, and the fact that shading operations may be wasted on surfaces which will be hidden in the final image.

Another method is the Multi-Pass lighting. Here, for each light, objects which are affected by the light are drawn with the current light’s shader. This causes a very high batch count (number of individual Draw calls), which in the worst case is equal to the number of lights multiplied by the number of objects. The problem of shading hidden surfaces still remains. And some operations are repeated many times each frame, such as vertex transformations.

Deferred Shading approaches the problem in a different manner. First, all objects are rendered without lighting computations. Instead, the objects output a set of attributes for each drawn pixel, such as position, normal, specular intensity, etc. After this, each light is applied on the final image as a 2D post process, using the data written in the previous pass. Because all objects use the same shader (the one which outputs the attributes), the engine management is greatly simplified. We no longed need to sort the scene objects based on the material they use. The number of draw calls is reduced to the number of objects + number of lights. Moreover, lighting calculations will only be done for visible pixels (the ones that make it into the final image).

Catalin has an excellent tutorial on deferred rendering, unfortunately some of the code no longer works, because it was written for XNA2.0.

Fortunately (for you) I’ve converted the entire code base to XNA4.0 as a learning exercise.

The code is a bit shorter now, (especially setting effects is so much easier in XNA4). And thus should be slightly easier to understand. The code includes everything that Catalin’s original source code examples included. The camera can be moved using the keyboard (arrows, or w-a-s-d to move, z and x to zoom) or using the Xbox controller.

The source code can be downloaded here: http://www.roy-t.nl/files/DeferredLightingXNA4.rar

As a little benchmarking tool, I’ve already turned of VSync and FixedTimeStep for you. On my modest machine (AMD Athlon GP9400 Quad Core, 4GB ram, and an AMD HD4850) I could easily render 600 lights at 60fps+. (However this looks ugly). The default settings (103 lights) runs at 380~400 fps.

Here’s a screen-shot how it should look (again by Catalin Zima)
Deferred Rendering

Anyway, have fun with it.

29 Responses to “Deferred Rendering in XNA4.0 Source Code”

  1. XNA 4.0 version of the Deferred Rendering code Says:

    [...] You can read all about it on Roy’s blog, here. [...]

  2. Proof Says:

    thanks for this, been waiting for someone to release a deferred rendering sample for XNA 4

  3. XDSK2 (XNA 4.0 Resources) | Nelxon Studio Says:

    [...] Deferred Rendering – Roy Triesscheijn updated Catalin Zima Tutorial to XNA 4.0 [...]

  4. Nelxon Says:

    Nice work Roy,

    I was going to convert this tutorial too. LOL
    I’ve added to this page to the XDSK2, deferred rendering is extremely useful.

    BTW, I’m sure you’re already pretty familiar with XNA 4.0 but if you need a cheat sheet converting XNA 3.1 to XNA 4.0,
    I created one on my website. XNA 3.1 to XNA 4.0 Cheat Sheet

  5. Roy Triesscheijn Says:

    @Proof

    Thanks for your comment :) .

    @Nelxon

    Ah seems like I beat you too it. Thanks for adding this to the XDSK2 aswell! I got quite a few tutorials/code samples on there now :D . I wish I found out earlier about your cheat sheet btw! Quite a few handy things on there!

  6. Assassini Says:

    Oh damn, I just finished porting the code about a week before this was posted. Well, it was a good learning exercise.

  7. Roy Triesscheijn Says:

    Ah yes, and that’s what really matters, I’m sure you understand the code much better now than if you would’ve just c/p’d this code instead.

  8. TECH :: DEFERRED RENDERING WITH XNA 4.0 « Game Developers Says:

    [...] new code has been developed by Roy Triesscheijn , a computer science student, which has released it in the open source [...]

  9. Tom Says:

    Great, saves me the trouble :) I’ll be digging through this to (hopelly) finally finish a proper deferred decal renderer…

    The original tutorial was a great resource, I only did snippets of it, but I’ll be doing the whole thing again soon to soak up as much as possible :) Too bad the tutorial itself is still 3.1 :(

  10. Roy Triesscheijn Says:

    Don’t worry about the tutorial being old, it’s mostly syntax that changed all the techniques still apply and the shader code is 100% the same.

  11. Devrunner Says:

    You’re the good man, thank you.

  12. Jack Says:

    Thanks for the updated tutorial. I am trying to follow the orginal tutorial through to understand what is going however I can’t seem to draw the render targets out to see what the gbuffer contains.

    spriteBatch.Draw(colorRT, new Rectangle(0, 0, halfWidth, halfHeight), Color.White);
    spriteBatch.Draw(normalRT, new Rectangle(0, halfHeight, halfWidth, halfHeight), Color.White);
    spriteBatch.Draw(depthRT, new Rectangle(halfWidth, 0, halfWidth, halfHeight), Color.White);

    I get the error “XNA Framework HiDef profile requires TextureFilter to be Point when using texture format Single.”

  13. Roy Triesscheijn Says:

    Hey Jack,

    In order to directly view the rendertargets on screen you need to begin the spritebatch using the overload to set the correct device state. Try this SpriteBatch.Begin overload: http://msdn.microsoft.com/en-us/library/ff433699.aspx and use SamplerState.Point for the sampler state and it should work.

  14. Nameless One Says:

    Hi Roy,

    thanks for the code. Just completed the conversion myself, hehe.
    About the number of Lights I can draw.. I can draw, with your code, amazing 2003 lights at around 25-30 fps. Counting in shadows and SSAO, it would probably be a lot less, but still more than with the old way. Thanks again,

    Nameless One ;)

  15. Magnus Says:

    Hello,

    When I run this code on my computer, I get artifacts at the edges of objects that are lit by point lights. The artifacts are interleaving dark and brighter stripes. Do you know why this happens and if so can it be fixed?

    best
    Magnus

  16. Roy Triesscheijn Says:

    Hey Magnus, without further info I wouldn’t know why. What kind of graphics card do you have? Might it be an Intel? They don’t support the more advanced features of DirectX very well.

  17. Christel Says:

    Hi Roy

    I’m having the same problem on my pc, i.e. artifacts that are dark and brighter stripes all over.

    My graphics card is an Nvidia 9600GT, so not brand new, but not too shabby.

    Here’s a link to a screenshot of a test scene rendered with the deferred renderer.

    Do you have any ideas of what could be the problem?

    Thanks
    Christel

  18. Christel Says:

    sorry about that here are the links properly:

    Test Scene Screenshot 1

    Test Scene Screenshot 2

  19. Roy Triesscheijn Says:

    Hey Christel,

    Could you also send me artifacts of how the light-map looks? Instead of displaying the final step on screen try using a spritebatch to display all buffers on screen (light, geometry, etc..) so that I can compare where the problem is. It does look light related, but I haven’t encountered this myself.

  20. Jannik Says:

    Maybe it has to do something with the normals? the black lines are aligned to vertices, not to screenspace dimensions

  21. CC Ricers Says:

    @Christiel It does look like a problem with the normals. Also it reminds me of per-vertex lighting interpolation which is odd given that all this happens in the pixel shader. Are your meshes made up of many rows of triangles?

  22. Christel Says:

    Sorry for taking so long to reply… I found my problem… seems I made a mistake and set the Surface Format of the Depth Buffer to Color instead of Single, changed that and it works perfectly now :)

  23. Ollhax Says:

    In case anyone else has the problem:

    When I ran this on the Xbox (simply made a xbox 360 copy of the deferred lighting project), I got some annoying flashing blue lines at the top of the screen. Looking closer, I realized that the lines were in fact cornflower blue – and after removing the GraphicsDevice.Clear(Color.CornflowerBlue) in Game1.cs, the problem disappeared. Guess you shouldn’t clear the screen twice, and that the Xbox is more picky about that.

  24. Garold Says:

    This is good. Really good. Got it running using my own house model and it looks very spooky and atmospheric, just what I wanted. I was using basiceffect which lit every face of the model. How do I add ambient light to the example so I can see in the dark corners of my rooms? I guess it’s sumfink to do wiv shaders :)

  25. Garold Says:

    I changed DeferredRenderer.cs to display only a single point light, to see :) what was going on. I added some code for ambient light in CombineFinal.fx, however, it is now making the black areas less black. Presumably I need to apply the ambient to the texture not the black pixel. Any ideas?

    float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
    {
    float3 diffuseColor = tex2D(colorSampler,input.TexCoord).rgb;
    float4 light = tex2D(lightSampler,input.TexCoord);
    float3 diffuseLight = light.rgb;
    float specularLight = light.a;
    return float4((AmbientColor * AmbientIntensity)+(diffuseColor * diffuseLight + specularLight),1);
    }

  26. Welcome to Project Vanquish! | Project Vanquish Says:

    [...] [...]

  27. Content Pipeline – Part 2 | Project Vanquish Says:

    [...] and “null_specular.tga”. You’ll need to extract these from Roy’s and add them to your “ProjectVanquishContent” [...]

  28. Natarajan Says:

    Please send me the steps in creating an anaglyph and also the source code of your software

  29. Roy Triesscheijn Says:

    Hey Natarajan,

    The anaglyph tutorial (with some source code) is here http://roy-t.nl/index.php/2011/05/08/xna-stereoscopic-3d-using-anyglyphs-and-redcyan-3d-glasses/





Or leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>