<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>MQuandt.Blog &#187; DirectX</title>
	<atom:link href="http://mquandt.com/blog/category/directx/feed/" rel="self" type="application/rss+xml" />
	<link>http://mquandt.com/blog</link>
	<description></description>
	<lastBuildDate>Wed, 25 Jan 2012 14:21:50 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
<cloud domain='mquandt.com' port='80' path='/blog/?rsscloud=notify' registerProcedure='' protocol='http-post' />
		<item>
		<title>Reconstructing Position from Depth for Fullscreen Quads</title>
		<link>http://mquandt.com/blog/2010/06/reconstructing-position-from-depth-for-fullscreen-quads/</link>
		<comments>http://mquandt.com/blog/2010/06/reconstructing-position-from-depth-for-fullscreen-quads/#comments</comments>
		<pubDate>Wed, 30 Jun 2010 02:56:35 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[DirectX]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[XNA]]></category>
		<category><![CDATA[depth]]></category>
		<category><![CDATA[frustum ray]]></category>
		<category><![CDATA[techniques]]></category>
		<category><![CDATA[tutorials]]></category>

		<guid isPermaLink="false">http://mquandt.com/blog/?p=108</guid>
		<description><![CDATA[Recently I found an issue with an older article of mine that covered this topic, so I pulled it down until I could find the time to understand and fix the issue. After a bit of work I have fixed it and present this refresh. The key to deferred rendering and other techniques is the &#8230; <a href="http://mquandt.com/blog/2010/06/reconstructing-position-from-depth-for-fullscreen-quads/">Read more <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Recently I found an issue with an older article of mine that covered this topic, so I pulled it down until I could find the time to understand and fix the issue. After a bit of work I have fixed it and present this refresh.</p>
<p>The key to deferred rendering and other techniques is the ability to use a depth map to store world position. As we know a depth map consists of floating point values (optimally) and so normally we would use those values with our Clip Space coordinates and the Inverse of the ViewProjection matrix to get the position in World Space.</p>
<p>However there is another way to do this, and the big benefit is that it does not require a matrix multiplication to do so.</p>
<p>Presented by Crytek during a presentation on Atmospheric Scattering, this method uses just a Multiply + Add to get the position in World Space from our depth value at that point. To do this we need to get the far view frustum corners, in View Space, and pass them to the shader.</p>
<p>  <span id="more-108"></span><br />
<h3>Getting the Corners</h3>
<p>This is easily done in XNA through the BoundingFrustum.GetCorners() method. Note that we only need the far corners, so we can take the last 4 in the 8 element array, and we also need these corners in View space, so be sure to transform them by the View matrix before you pass them through.</p>
<pre class="brush: csharp;">private void getFrustumCorners(out Vector3[] corners)
{
    corners = new Vector3[4];

    Vector3[] temp = CurrentCamera.Frustum.GetCorners();
    for (int i = 0; i &lt; 4; i++)
    {
        corners[i] = Vector3.Transform(temp[i + 4], CurrentCamera.View);
    }
}</pre>
<p>Since we are in the CPU/XNA code, be sure to also pass the depth of the far clip plane, and the camera’s World matrix. (Simply invert the View matrix if you do not already have a World matrix)</p>
<h3>Writing out Depth</h3>
<p>Now for some shader code! First in the depth shader, you need to change how you write out the depth value, instead we take the Linear View Space depth, which means that we need to get the Z value from Position * World * View rather than Position * World * View * Projection.</p>
<pre class="brush: cpp;">float4x4 wv = mul( World, View );
float4 posVS = mul( pos, wv );

output.Position = mul( posVS, Projection );
output.Depth = posVS.z;</pre>
<p>Then in the pixel shader, take this depth value, negate it and divide it by the Far Clipping plane.</p>
<pre class="brush: cpp;">output.Depth = 1.0f - ( -depth / FarClip );</pre>
<p>Now when you want to reconstruct this, we need to find the correct frustum corner inside the vertex shader. (Note: This code only applies if you are rendering a fullscreen quad)</p>
<h3>Preparing and Choosing the Right Corner</h3>
<p>The best way to do this is to pass along the array index as a 3rd value with your texture coordinates. If you do not want to modify the vertex type, you can also apply some maths to determine the right index.</p>
<p>For brevity I will assume that the index is provided with the texture coordinates.</p>
<p>Take that ray and multiply it by the camera World matrix, to move the ray into World space, then pass it to the pixel shader.</p>
<pre class="brush: cpp;">output.FrustRay = mul( FSQ_GetFrustumRay( tcri.z ), CamWorld );</pre>
<h3>Getting the Position</h3>
<p>Now that you have the ray, simply sample the depth texture for the depth value, and multiply it by the ray. Then take that and add it to the camera position to get the point in world space. (Rather than just a direction)</p>
<pre class="brush: cpp;">float depth = 1.0f - tex2D( depthSampler, tc ).x;
float3 pos = CamPosition + depth * frustRay;</pre>
<p>Now you have your position!</p>
<p>I will include the technique to do the same thing with arbitrary world geometry when I write an article on Point Lights or Spotlights. At the moment I am working on implementing shadows, and probably won’t touch those topics until I solve some pressing issues.</p>
<h3>Final Notes</h3>
<p>Here is a code sample for passing the index as a part of the texture coordinate value.</p>
<p>&#160;</p>
<pre class="brush: csharp;">private struct VertexPositionTexCoordRayIndex
{
    private Vector3 position;
    public Vector3 Position
    {
        get { return position; }
        set { position = value; }
    }

    private Vector3 texCoordRayIndex;
    public Vector3 TexCoordRayIndex
    {
        get { return texCoordRayIndex; }
        set { texCoordRayIndex = value; }
    }

    public static int SizeInBytes { get { return sizeof(float) * 6; } }

    public static readonly VertexElement[] VertexElements =
        new VertexElement[] {
            new VertexElement(0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0),
            new VertexElement(0, sizeof(float)*3, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.TextureCoordinate, 0)
        };

    public VertexPositionTexCoordRayIndex(Vector3 position, Vector3 texcoordRayindex)
    {
        this.position = position;
        this.texCoordRayIndex = texcoordRayindex;
    }
}</pre>
<pre class="brush: csharp;">VertexPositionTexCoordRayIndex[] verts = new VertexPositionTexCoordRayIndex[4];
verts[0] = new VertexPositionTexCoordRayIndex(new Vector3(-1, 1, 1), new Vector3(0, 0, 0));
verts[1] = new VertexPositionTexCoordRayIndex(new Vector3(1, 1, 1), new Vector3(1, 0, 1));
verts[2] = new VertexPositionTexCoordRayIndex(new Vector3(-1, -1, 1), new Vector3(0, 1, 3));
verts[3] = new VertexPositionTexCoordRayIndex(new Vector3(1, -1, 1), new Vector3(1, 1, 2));</pre>
<p>&#160;</p>
<p>Remember that XNA provides the corners in a different order to just 1,2,3,4, so we can explicitly pass the correct index for the vertex we are working with here, and it will be chosen correctly in the shader.</p>
]]></content:encoded>
			<wfw:commentRss>http://mquandt.com/blog/2010/06/reconstructing-position-from-depth-for-fullscreen-quads/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Status June 2010</title>
		<link>http://mquandt.com/blog/2010/06/status-june-2010/</link>
		<comments>http://mquandt.com/blog/2010/06/status-june-2010/#comments</comments>
		<pubDate>Thu, 17 Jun 2010 22:52:20 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[DirectX]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[XNA]]></category>
		<category><![CDATA[light pre pass]]></category>
		<category><![CDATA[status]]></category>
		<category><![CDATA[techniques]]></category>
		<category><![CDATA[tutorials]]></category>

		<guid isPermaLink="false">http://mquandt.com/blog/2010/06/status-june-2010/</guid>
		<description><![CDATA[Hi all, not dead. Apologies for the lack of updates, I am in the process of finishing an internship required for my university course, and it is a challenge to find good time to tackle some XNA issues and write posts. I am currently working on Directional light shadows for my engine, I have cascaded &#8230; <a href="http://mquandt.com/blog/2010/06/status-june-2010/">Read more <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Hi all, not dead.</p>
<p>Apologies for the lack of updates, I am in the process of finishing an internship required for my university course, and it is a challenge to find good time to tackle some XNA issues and write posts.</p>
<p>I am currently working on Directional light shadows for my engine, I have cascaded shadow maps implemented, and now I am just tackling some issues I have encountered, which is taking a while – I also need to find a good filtering method.</p>
<p>If I get bored of trying to fix those annoying issues, I will probably jump into re-implementing point lights, and spotlights, and write something about those.</p>
<p>Some housekeeping notes:</p>
<p>I encountered a pretty big issue with the “Reconstructing position from depth” technique, and I have taken that article down from the blog for now. At the moment my own code uses the old “Multiply my the Inverse of the View Projection matrix”, and probably will continue to until I have time to solve that problem.</p>
<p>I have also updated this blog to WordPress 3.0, so let me know if you encounter any issues.</p>
<p>Back to work.</p>
]]></content:encoded>
			<wfw:commentRss>http://mquandt.com/blog/2010/06/status-june-2010/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[LPP] Ambient Lights</title>
		<link>http://mquandt.com/blog/2010/04/lpp-ambient-lights/</link>
		<comments>http://mquandt.com/blog/2010/04/lpp-ambient-lights/#comments</comments>
		<pubDate>Sat, 03 Apr 2010 01:32:01 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[DirectX]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[XNA]]></category>
		<category><![CDATA[ambient lights]]></category>
		<category><![CDATA[light pre pass]]></category>

		<guid isPermaLink="false">http://mquandt.com/blog/2010/04/lpp-ambient-lights/</guid>
		<description><![CDATA[Ambient lights are used in modern games to fake the indirect illumination that exists in the real world. By adding a generally very weak light to the scene, we can avoid the 100% black shadows that really should not exist, all at a very low cost compared to proper indirect illumination or baked ambient light &#8230; <a href="http://mquandt.com/blog/2010/04/lpp-ambient-lights/">Read more <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Ambient lights are used in modern games to fake the indirect illumination that exists in the real world. By adding a generally very weak light to the scene, we can avoid the 100% black shadows that really should not exist, all at a very low cost compared to proper indirect illumination or baked ambient light maps.</p>
<p>I have found that the simplest way to integrate these ambient lights into the Light Pre Pass system, and allow for other elements to change the lights throughout the game is to create a new light type that fits into the normal lighting model.</p>
<p>This is probably the simplest type out there, you just create a full screen quad and render it using a shader that writes the colour information directly to the light buffer. All we have to pass to the shader is the colour and intensity. (you could always pre-compute this, but beware of the byte-&gt;int32 auto promotion C# does)</p>
<p> <span id="more-101"></span>
<p>Here is the C# class:</p>
<pre class="brush: csharp;">public class AmbientLight
{
    public Color Color { get; set; }

    public bool Enabled { get; set; }

    private int intensity = 100;

    public int Intensity
    {
        get { return intensity; }
        set { intensity = value; }
    }

    private Effect shader;

    public AmbientLight(Color col, int intensity)
    {
        this.Color = col;
        this.Enabled = true;
        this.intensity = intensity;
    }

    public void LoadContent(ContentManager content)
    {
        shader = content.Load&lt;Effect&gt;(@&quot;Effects\Lights\l_ambient&quot;);
    }

    public void DrawLight(Renderer caller)
    {
        if (!Enabled)
            return;

        shader.Begin();
        shader.Parameters.TrySet(&quot;LightColor&quot;, Color.ToVector3());
        shader.Parameters.TrySet(&quot;Intensity&quot;, intensity);

        shader.CurrentTechnique.Passes[0].Begin();
        caller.FSQ.Draw();
        shader.CurrentTechnique.Passes[0].End();

        shader.End();
    }
}</pre>
<p>and the shader:</p>
<pre class="brush: cpp;">float3 LightColor;
float Intensity;

float4 vs_main(in float4 pos : POSITION) : POSITION
{
    return pos;
}

float4 ps_main() : COLOR
{
    return float4(LightColor * (Intensity / 100), 0);
}

technique AmbientLight
{
    pass p0
    {
        VertexShader = compile vs_2_0 vs_main();
        PixelShader = compile ps_2_0 ps_main();
    }
}</pre>
<p>I am in the middle of a crunch at work, and so future posts will be slow until it is all over. (That is why this one took a while to come out) I have not had the chance to do much work on my own XNA code, let alone tutorials. <img src='http://mquandt.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Thanks for your patience, I cannot wait to get back to XNA. (and I cannot wait for XNA 4.0 with HiDef)</p>
]]></content:encoded>
			<wfw:commentRss>http://mquandt.com/blog/2010/04/lpp-ambient-lights/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Light Pre-Pass Round 2</title>
		<link>http://mquandt.com/blog/2010/03/light-pre-pass-round-2/</link>
		<comments>http://mquandt.com/blog/2010/03/light-pre-pass-round-2/#comments</comments>
		<pubDate>Thu, 11 Mar 2010 12:20:58 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[DirectX]]></category>
		<category><![CDATA[Games]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[XNA]]></category>
		<category><![CDATA[light pre pass]]></category>
		<category><![CDATA[tutorials]]></category>

		<guid isPermaLink="false">http://mquandt.com/blog/2010/03/light-pre-pass-round-2/</guid>
		<description><![CDATA[Those who have been following this blog know that I wrote an article about implementing a Light Pre-Pass renderer last year. Since then I have made numerous improvements and fixes as I have tried the system over different PC configurations. This time around I will be including those changes into the implementation, and also releasing &#8230; <a href="http://mquandt.com/blog/2010/03/light-pre-pass-round-2/">Read more <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Those who have been following this blog know that I wrote an article about implementing a Light Pre-Pass renderer last year. Since then I have made numerous improvements and fixes as I have tried the system over different PC configurations.</p>
<p>This time around I will be including those changes into the implementation, and also releasing sample code for educational use. If you feel you have learned enough from the previous article, then feel free to skip this. For those new to the topic, please use this article instead of the older one.</p>
<p> <span id="more-96"></span>
</p>
<p>This article will focus on the theory, and will attempt to be as API neutral as possible. I will be making some references to XNA SurfaceFormats as this article is aimed more towards XNA developers, but for reference here are the matching Direct3D formats:</p>
<table border="0" cellspacing="0" cellpadding="2" width="400">
<tbody>
<tr>
<td valign="top" width="200">SurfaceFormat.Color</td>
<td valign="top" width="200">A8R8G8B8</td>
</tr>
<tr>
<td valign="top" width="200">SurfaceFormat.Bgra1010102</td>
<td valign="top" width="200">A2R10G10B10</td>
</tr>
<tr>
<td valign="top" width="200">SurfaceFormat.Single</td>
<td valign="top" width="200">R32F</td>
</tr>
<tr>
<td valign="top" width="200">SurfaceFormat.HalfSingle</td>
<td valign="top" width="200">R16F</td>
</tr>
</tbody>
</table>
<p>See the sample for an XNA implementation.</p>
<h3>General Overview</h3>
<p>For a number of years now, the concept of Deferred Rendering has been a hot topic in games. The ability to have a large number of lights, with a low cost per light is an attractive option. However deferred rendering suffers from the inability to render transparent objects at the same time as opaque objects. A few “solutions” have appeared in recent years that approach deferred rendering in a different way to allow for some level of transparency, however none have solved the problem completely, and all require extra work in some form.</p>
<p>There are a few different types of Deferred Rendering, however the two key forms are Deferred Shading, and Deferred Lighting. These differ in exactly which stage of rendering is deferred.</p>
<p>Deferred Shading defers the entire shading and lighting process, handling geometry rendering once, and then using an Uber Shader to light and shade the objects. One of the key negatives here is that you are limited in your material selection – although there are a few alternative solutions that can help here. Some other negatives include the “Fat Framebuffer” that this technique requires. As Deferred Shading relies on Multiple Render Targets (MRTs) to render the geometry once and store all important details, we are hit with both a memory cost, as well as limitations in DirectX9 which prevent us from applying multi-sampling (AA) to MRTs.    <br />Negatives aside, Deferred Shading allows us to get the benefit of many lights, and still only render the scene once, which can be good for performance in scenes where the triangle count is high, and you do not need a diverse set of materials.</p>
<p>Deferred Lighting on the other hand defers only the lighting step, and requires an extra pass over the geometry to apply the details. The benefit here is that you can apply a unique material to each of your objects, whilst retaining the ability to have many lights. This technique also makes use of MRTs, however it only uses 2 render targets during the Depth + Normals stage, so if you can afford another pass over geometry, you can split those into two passes and gain the ability to run code on older hardware that does not support MRTs.</p>
<h3>Deferred Lighting Overview</h3>
<p>Deferred Lighting consists of 3 key stages:<img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="LPP Pipeline" border="0" alt="LPP Pipeline" src="http://mquandt.com/blog/wp-content/uploads/2010/03/lpp_pipeline_thumb.png" width="481" height="200" /></p>
<ol>
<li>Render the Depth and World Space Normals of the Geometry </li>
<li>Render the lighting term using the Depth + Normals generated previously </li>
<li>Render the Geometry again, this time with unique materials, making use of the lighting term above. </li>
</ol>
<p>Remember that if you retain your hardware depth stencil, you get a performance increase from the early-z tests that modern hardware provides.</p>
<p>One key optimisation that is used in Deferred Shading is to render the lights using bounding volumes, ie a Sphere for a Point Light. This prevents overdraw for areas that are not lit.</p>
<p>I will be following the steps mentioned above, with the aforementioned optimisation, for the rest of this article.</p>
<h3>Stage 1: Depth + Normals</h3>
<p>The key requirement for any lighting calculation is fragment position, and normal. This means that if we want to determine the contribution a light makes to a particular pixel, we need to know where in world space that pixel is, and the normal at that pixel.</p>
<p>As we are deferring the lighting calculations, we need to store this information in a format we can use later. Now to store a position, we could go the naive route and store one component per channel, i.e. R=X, G=Y and B=Z, however this only gives us 8 bits of precision for each component, and each component is a full 32bit floating point number.</p>
<p>Instead we store the depth of the pixel and later reconstruct the position using the depth, and information from the camera.</p>
<p>Unfortunately, as we are working with XNA, we are restricted to D3D9 technology, and even then cannot use the FOURCC driver hacks that modern GPUs provide. This means that we have to write out the depth buffer to a separate render target instead of making use of the depth buffer the graphics card always creates.</p>
<p>So begin by preparing two render targets, the same size as the backbuffer you are going to draw to in the end. Make the depth target use SurfaceFormat.Single, and the Normals target use SurfaceFormat.Bgra1010102.</p>
<p>Of course when implementing this in a game for Windows, you should always verify that the SurfaceFormats are supported, and in the case of the depth buffer you can fall back to HalfSingle if Single is not supported. The Normal buffer can fall back to SurfaceFormat.Color if the 1010102 format is not supported, and you can always take the depth buffer back to Color if you absolutely need to, however note that you will need to add in extra packing code to make use of the full buffer then.</p>
<p>After that, we need to render the visible scene using a special shader that writes the Depth and Normal information to our render targets.</p>
<p>There are two key things to note here:</p>
<ol>
<li>If you decide to subtract the true depth from 1.0f, ensure you reverse that later on. </li>
<li>You need to remap the Normal from [-1, 1] to [0, 1] so that it stores correctly in the render target </li>
</ol>
<p>To accomplish #2, you simply need to use the following equation:</p>
<pre>output.Normal = (( input.Normal + 1.0f ) / 2.0f )</pre>
<p>Later on we will return this value to the [-1, 1] range by using the reverse of the above equation.</p>
<h3>Stage 2: Lighting</h3>
<p>Now that we have the Depth and Normal for each pixel, we can calculate the lighting from every light that touches each pixel. If you plan to include some form of shadow mapping, this is where you would handle rendering the shadow maps, and make use of them when lighting the object.</p>
<p>You can approach lighting in two ways:</p>
<ol>
<li>Render every type of light as a fullscreen quad. </li>
<li>Render each light as an appropriate light volume [<a href="http://developer.nvidia.com/object/6800_leagues_deferred_shading.html">Hargreaves04</a>] </li>
</ol>
<p>We will focus on #2, which allows us to reduce pixel draw and improve performance dramatically.</p>
<p align="left">Although I will only be implementing a Directional Light in the sample, you can use the following primitives to render each type of light:</p>
<table border="0" cellspacing="0" cellpadding="2" width="400">
<tbody>
<tr>
<td valign="top" width="200">Ambient Light</td>
<td valign="top" width="200">Fullscreen Quad</td>
</tr>
<tr>
<td valign="top" width="200">Directional Light</td>
<td valign="top" width="200">Fullscreen Quad</td>
</tr>
<tr>
<td valign="top" width="200">Point Light</td>
<td valign="top" width="200">Sphere</td>
</tr>
<tr>
<td valign="top" width="200">Spot Light</td>
<td valign="top" width="200">Cone or Box</td>
</tr>
</tbody>
</table>
<p align="left">As you can see, the two light types that do not have a position or volume, are still rendered as fullscreen quads, whilst the other two use approximations of their light volumes to prevent overdraw</p>
<p>In the case of the ambient light, you may choose to implement this as an extra term in your material shader instead, however I choose to implement it as a light object so that I may alter/combine/disable at will.</p>
<p>Here you need to set a new render target, which will hold our Light Buffer. Once that is done, render each visible light volume using a special shader based on the light type.</p>
<p>This is where the magic happens. Inside these special shaders, we reconstruct the world space position of the pixel from the depth value, and using the position and the normal, calculate the lighting term as you would during forward rendering.</p>
<p>There are a couple of ways you can reconstruct the position from the depth value. The most common and obvious way would be to use the X/Y value of the pixel in Post-Projection Space, combined with the depth as Z, and multiply that by the inverse of the ViewProjection matrix. This will give you the position of the pixel in World space, which you can use.</p>
<p>There are other techniques, some which end up cheaper than the matrix multiply mentioned above. For a full overview of most (if not all) of the techniques available for you to use, simply read through these two articles:</p>
<p><a href="http://mynameismjp.wordpress.com/2009/03/10/reconstructing-position-from-depth/">http://mynameismjp.wordpress.com/2009/03/10/reconstructing-position-from-depth/</a> </p>
<p><a href="http://mynameismjp.wordpress.com/2009/05/05/reconstructing-position-from-depth-continued/">http://mynameismjp.wordpress.com/2009/05/05/reconstructing-position-from-depth-continued/</a></p>
<p>In the sample I chose to use the Frustum Ray method, which is a cheaper way to get the position, but requires you to do some processing on the CPU to get the rays ready. In the sample this is calculated every time the camera parameters are set, however realistically you only need to do this any time your bounding frustum changes or moves.</p>
<p>Our light buffer, which is a SurfaceFormat.Color, can take four 8bit integers. The original, and (to my knowledge) recommended layout (from Wolfgang Engel) is to store the <strong>N</strong>.<strong>L</strong> * Color terms in the RGB channels, and the specular term in the Alpha channel. This leaves you with the following layout:</p>
<table border="0" cellspacing="0" cellpadding="2" width="231">
<tbody>
<tr>
<td valign="top" width="31">A</td>
<td valign="top" width="198"><strong>R</strong>.<strong>V</strong> (or <strong>N</strong>.<strong>H</strong> for Blinn-Phong)</td>
</tr>
<tr>
<td valign="top" width="31">R</td>
<td valign="top" width="198"><strong>N</strong>.<strong>L</strong> * Red</td>
</tr>
<tr>
<td valign="top" width="31">G</td>
<td valign="top" width="198"><strong>N</strong>.<strong>L</strong> * Green</td>
</tr>
<tr>
<td valign="top" width="31">B</td>
<td valign="top" width="198"><strong>N</strong>.<strong>L</strong> * Blue</td>
</tr>
</tbody>
</table>
<p>At this point you can also take into account the shadow map for each light, and use that to choose whether this light should illuminate or do nothing to the pixel. Now when rendering the lights, we need to set a couple of Render States to ensure things go smoothly.</p>
<p>First of all, we need to ensure that the depth buffer is disabled. This has to happen because we may need to render lights behind/inside other lights, and if the depth buffer is enabled, the graphics card will reject the contribution from some of those lights via the Early-Z feature.</p>
<p>Since we are using geometry to render the lighting, we need to handle the case when the camera is inside the light volume. Here we change the CullMode render state so that it either culls interior faces when the camera is outside the object, or it culls exterior faces when the camera is inside the object. Normally this would be set to Counter-Clockwise, which remains our default when outside the object.</p>
<p>Simply detect when the camera is inside the object and set the CullMode to Clockwise to handle the other case.</p>
<p>Another issue you may notice with this is when the camera is entering a light volume, especially the point light sphere. At this point, part of the screen is inside the object, and the rest is outside, so we need to set CullMode to None here to handle both cases without creating visual glitches.</p>
<p>Finally we need to enable alpha blending and set the blend mode to Add, this allows multiple lights that illuminate the same pixel to combine correctly (see <a href="http://en.wikipedia.org/wiki/Phong_shading">Phong Shading</a>).</p>
<p>Do not forget to re-enable the Depth Buffer and revert the CullMode to Counter-Clockwise before continuing, otherwise you might encounter hard to debug issues when rendering the materials.</p>
<h3>Stage 3: Materials</h3>
<p>Once the light buffer has been filled with all of the visible lights, you can move on to rendering the final image using each object’s material. First you need to make sure that all of your Render States are back to normal after the changes made during the Lighting stage.</p>
<p>To render the materials, you need to re-render every object that was drawn during the Depth + Normals stage, however this time around each object can use its own shader to draw itself, and can take the Light buffer as a texture, which can then be used as the lighting term when shading.</p>
<p>There are numerous effects that can be used to shade an object. In the sample I will only provide a Blinn-Phong shader, however as long as you understand the basic concepts of lighting in modern graphics, you can adapt the lighting values into any other technique that can use them.</p>
<p>This is where I find the big benefits of this technique appear. By allowing the object to choose its own shader/material, you can regain the diverse range of materials that forward rendering allows, providing your artists with plenty of possibilities. Not only that, but you do not have to manage a monster Uber Shader, balancing it against potentially restrictive instruction/texture count limits. (Depending on your Shader Model)</p>
<p>The sample will show how to implement a Blinn-Phong lighting model, with a textured object.</p>
<p>On the other hand, the big negative of this technique appears here as well. You now have to re-render every object a second time. Depending on your scene, this could be a reasonable performance hit. So ensure you weigh up both options when choosing your renderer for your game, and consider what you will need when choosing.</p>
<h3>Transparency/Anti-aliasing</h3>
<p>Transparency and Anti-Aliasing have traditionally been a major problem when it comes to Deferred Rendering. The need to render a Depth buffer has prevented the ability to do any reasonable form of transparency aside from the basic Invisible/Opaque states. There are a few solutions to this issue, although none solve it perfectly.</p>
<ol>
<li>Render your transparent objects using traditional forward rendering, with a limited number of lights, and composite the transparency scene into your deferred scene. </li>
<li>Use stippling to alternate between layers on a high resolution render target. This is used in the recent articles on Inferred Rendering. </li>
<li>Use Order Independent Transparency/Depth Peeling, which can be fairly expensive. (See DX SDK Feb 2010 Samples) </li>
</ol>
<p>I would recommend using option #1 and constructing your scenes so that the only transparent objects are particles, which can be lit with a small number of lights for little to no visual impact.</p>
<p>Anti-Aliasing has also been a problem for Deferred Renderers, primarily because DirectX 9 does not allow for AA with multiple render targets. DirectX 10 allows this, and fixes the issue, however since my target here is XNA, this is not possible.</p>
<p>Traditionally the AA issue was solved by using an Edge Detection filter + Blur to soften the edges of objects, this is relatively cheap and can be implemented as a post processing effect.</p>
<p>However for those interested in taking advantage of the AA modes of modern graphics cards, with very crisp edges, LPP provides a way to have your cake and eat it. (With a small cost)</p>
<p>As there are only 2 Render Targets needed during the Depth + Normals pass, and one at a time after that, you can split that pass up and render the scene an extra time, this time with AA enabled for each step. Of course if you have high scene complexity this might be extremely expensive and not worth it, but the option is there, and it is up to you and the needs of your game.</p>
<h3>Conclusion</h3>
<p>You now have a backbuffer (or Render Target) filled with your shaded scene, ready for further post processing, or presentation to the user. By using this technique you gain the ability to have thousands of lights in your scene at once, which allows level designers and artists to really let loose with their creativity.</p>
<p>Simply having this sheer number of lights also opens up other possibilities for lighting, including fake indirect lighting, a technique that as not been easy to do dynamically. You can assign point lights to every particle in your scene, and really make your worlds much more vibrant.</p>
<p>Also remember that you have a Depth and Normal buffer available for free (you needed it for LPP anyway) for use in post processing, which allows you to add other techniques like SSAO to your game.</p>
<p>Deferred Rendering seems to be the &quot;cool thing” in game graphics today, and with the Compute Shader/OpenCL becoming readily available, some of these techniques can be adapted to make use of the general purpose capabilities of modern graphics cards.</p>
<p>Whilst there are plenty of benefits, there are also negatives to using this technique, and you really need to think about what you want out of your renderer before making your final decision. There have been plenty of debates in the graphics world about whether Deferred Rendering is better than Forward Rendering, and I am not going to go into one of those today.</p>
<h3>Further Reading</h3>
<p>For more information about Deferred Lighting/Light Pre Pass, you can check out the following books/websites:</p>
<ul>
<li><a href="http://diaryofagraphicsprogrammer.blogspot.com/">http://diaryofagraphicsprogrammer.blogspot.com/</a> </li>
<li>Section8, Chapter 5; ShaderX7, Wolfgang Engel, Course Technology [ISBN: 1584505982] </li>
<li><a title="http://www.bungie.net/images/Inside/publications/siggraph/Engel/LightPrePass.ppt" href="http://www.bungie.net/images/Inside/publications/siggraph/Engel/LightPrePass.ppt">http://www.bungie.net/images/Inside/publications/siggraph/Engel/LightPrePass.ppt</a> (SIGGRAPH 2009) </li>
</ul>
<h3>Sample</h3>
<p>I have written a sample implementation of the Deferred Lighting/Light Pre Pass renderer using XNA 3.1. Feel free to learn from this implementation, and if you have any questions, just ask in the comments.</p>
<p>The code provided in the sample is for Academic Use Only, and cannot be copied into a Commercial program.</p>
<p>This sample shows off 6 directional lights around a single model taken from the DirectX SDK. Feel free to add more lights as you please. I have only implemented Directional lights for this sample, to keep things simple. I will provide information on implementing other lights soon, however in the meanwhile feel free to look at my previous (now obsolete) article for a point light implementation, which should be similar.</p>
<p>You can download the sample <a href="http://cid-670fd4ae41402e8a.skydrive.live.com/self.aspx/Public/LPPSample.zip" target="_blank">here</a>.</p>
<p>Controls:</p>
<p>1 : Show Depth Buffer<br />
  <br />2 : Show Normal Buffer </p>
<p>3 : Show Lights Buffer </p>
<p>4 : Show Material Buffer</p>
<p>W : Move Forward<br />
  <br />S : Move Backward </p>
<p>A : Strafe Left </p>
<p>D : Strafe Right </p>
<p>Left Arrow : Rotate Left </p>
<p>Right Arrow : Rotate Right</p>
]]></content:encoded>
			<wfw:commentRss>http://mquandt.com/blog/2010/03/light-pre-pass-round-2/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>An update on LPP + Sample</title>
		<link>http://mquandt.com/blog/2010/02/an-update-on-lpp-sample/</link>
		<comments>http://mquandt.com/blog/2010/02/an-update-on-lpp-sample/#comments</comments>
		<pubDate>Sun, 21 Feb 2010 04:48:41 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[DirectX]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[XNA]]></category>
		<category><![CDATA[game engine gems]]></category>
		<category><![CDATA[game programming gems]]></category>
		<category><![CDATA[gpu pro]]></category>
		<category><![CDATA[light pre pass]]></category>
		<category><![CDATA[sample code]]></category>

		<guid isPermaLink="false">http://mquandt.com/blog/2010/02/an-update-on-lpp-sample/</guid>
		<description><![CDATA[Hi everyone, first of all apologies for the delay. there has been quite a lot going on in my life, but I am working hard on getting the sample done. This time around I wanted to make sure I had a sample ready to go with the article, especially since the article will focus on &#8230; <a href="http://mquandt.com/blog/2010/02/an-update-on-lpp-sample/">Read more <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Hi everyone, first of all apologies for the delay. there has been quite a lot going on in my life, but I am working hard on getting the sample done. This time around I wanted to make sure I had a sample ready to go with the article, especially since the article will focus on the technique and theory and have little to no code – although I will certainly focus on XNA when it comes to mentioning issues and benefits to certain parts.</p>
<p>One of the main delays was getting the sample code out of my engine, and cleaning it up so it can be used as a learning tool. Unfortunately most of the code was hacked on as I fixed issues in the LPP renderer, and added features.</p>
<p>I have a fair bit of the article written, however recently I was implementing shadows and realised that I never thought about how they would integrate into the system, so I decided to rewrite my own renderer (which should not take long) and at the same time keep the code clean so it can serve as a sample as well.</p>
<p>This means I will probably also have Directional Light shadows in the sample. This then allows me to write about point lights, and spotlights later on, and include shadows for both.</p>
<p>So again, sorry for the delay, I am working hard to get it out soon.</p>
<p>As an aside, I noticed that Game Programming Gems is getting an 8th Edition, something I was not expecting, so with that, GPU Pro, and Game Engine Gems, I might be able to find some more cool things to write about.</p>
<p>Thank You for your patience.</p>
]]></content:encoded>
			<wfw:commentRss>http://mquandt.com/blog/2010/02/an-update-on-lpp-sample/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Autodesk Student Subscriptions [Freebies]</title>
		<link>http://mquandt.com/blog/2010/01/autodesk-student-subscriptions-freebies/</link>
		<comments>http://mquandt.com/blog/2010/01/autodesk-student-subscriptions-freebies/#comments</comments>
		<pubDate>Sat, 09 Jan 2010 12:26:56 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[DirectX]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[XNA]]></category>
		<category><![CDATA[3ds max]]></category>
		<category><![CDATA[autodesk]]></category>
		<category><![CDATA[maya]]></category>

		<guid isPermaLink="false">http://mquandt.com/blog/2010/01/autodesk-student-subscriptions-freebies/</guid>
		<description><![CDATA[I know that many of you will want to make use of either Blender or the nice free version of Softimage (Previously XSI) on the Creators Club website, however for those interested in expanding their skill set, perhaps with the intention of entering the industry, getting access to 3ds Max or Maya can be quite &#8230; <a href="http://mquandt.com/blog/2010/01/autodesk-student-subscriptions-freebies/">Read more <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I know that many of you will want to make use of either Blender or the nice free version of Softimage (Previously XSI) on the Creators Club website, however for those interested in expanding their skill set, perhaps with the intention of entering the industry, getting access to 3ds Max or Maya can be quite hard to do.* (legitimately)</p>
<p>I recently found that if you are a student and have an email address with your institution (.edu) then you can get access to licenses for Max, Maya, even AutoCAD and Revit for free using the Autodesk Student subscription.</p>
<p>Just go to <a href="http://students.autodesk.com">http://students.autodesk.com</a> to see if you qualify and register.</p>
<p><em>* I am not implying that 3ds Max + Maya are the only tools the industry uses, however they are the focus of this post.</em></p>
<p>Side Note: There are way too many versions of AutoCAD.</p>
]]></content:encoded>
			<wfw:commentRss>http://mquandt.com/blog/2010/01/autodesk-student-subscriptions-freebies/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rewrite of LPP Article Planned</title>
		<link>http://mquandt.com/blog/2009/12/rewrite-of-lpp-article-planned/</link>
		<comments>http://mquandt.com/blog/2009/12/rewrite-of-lpp-article-planned/#comments</comments>
		<pubDate>Sat, 12 Dec 2009 15:54:25 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[DirectX]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Xbox 360]]></category>
		<category><![CDATA[XNA]]></category>
		<category><![CDATA[light pre pass]]></category>
		<category><![CDATA[xbox 360]]></category>

		<guid isPermaLink="false">http://mquandt.com/blog/2009/12/rewrite-of-lpp-article-planned/</guid>
		<description><![CDATA[I recently went about making the current Light Pre Pass system run on the XBOX 360, and had to fix some issues that appeared there. As a result, the next article to go up will be a rewrite with all of these fixes included. I should also be able to provide the sample code at &#8230; <a href="http://mquandt.com/blog/2009/12/rewrite-of-lpp-article-planned/">Read more <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I recently went about making the current Light Pre Pass system run on the XBOX 360, and had to fix some issues that appeared there. As a result, the next article to go up will be a rewrite with all of these fixes included. I should also be able to provide the sample code at the same time.</p>
<p>This time around I will cover Point, Ambient and Directional lights in the same post, as well as including information about an alternate light buffer format that allows for improved specular + per-material specular.</p>
<p>Expect this either during the weekend of 20-21st Dec, or shortly after that.</p>
<p>Unfortunately I could not test the code on the XBOX the first time around due to subscription issues, however everything is fine now, and I can and will test on both XBOX and my desktop PC beforehand. (Perhaps also other PC configs depending on who I can find online at the time, and what other machines I have on hand <img src='http://mquandt.com/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  )</p>
]]></content:encoded>
			<wfw:commentRss>http://mquandt.com/blog/2009/12/rewrite-of-lpp-article-planned/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Important Additions &amp; Fixes to LPP Implementation</title>
		<link>http://mquandt.com/blog/2009/12/important-additions-fixes-to-lpp-implementation/</link>
		<comments>http://mquandt.com/blog/2009/12/important-additions-fixes-to-lpp-implementation/#comments</comments>
		<pubDate>Fri, 04 Dec 2009 06:04:31 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[DirectX]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[XNA]]></category>

		<guid isPermaLink="false">http://mquandt.com/blog/?p=70</guid>
		<description><![CDATA[I have finally tracked down an issue that I was having with the Light Pre Pass implementation, and as a result have had to make some changes to the implementation. Firstly, I would recommend ensuring RenderState.AlphaTestEnable is false before rendering materials, it appears this is set (at least in my sample) somewhere and it corrupts &#8230; <a href="http://mquandt.com/blog/2009/12/important-additions-fixes-to-lpp-implementation/">Read more <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I have finally tracked down an issue that I was having with the Light Pre Pass implementation, and as a result have had to make some changes to the implementation.</p>
<p>Firstly, I would recommend ensuring RenderState.AlphaTestEnable is <strong>false</strong> before rendering materials, it appears this is set (at least in my sample) somewhere and it corrupts the light buffer.</p>
<p>Secondly, move the postProjToScreen and halfPixel calls from the vertex shader in blinnphong.fx, to the pixel shader. Some GPUs (like my laptop&#8217;s) do not correctly interpolate the adjusted screen coordinates, and this ensures it is correctly interpolated per pixel.</p>
<pre class="brush: cpp;">gfx.SetRenderTarget(0, light);
gfx.SetRenderTarget(1, null);
depthImage = depth.GetTexture();
normImage = normals.GetTexture();
gfx.RenderState.AlphaTestEnable = false;</pre>
<p>Finally, when writing the Normal in the vertex shader for def_depthnorm.fx, swap the parameters of mul(input.Normal, World) to mul(World, input.Normal).</p>
<p>That should be all, if you notice any other issues, feel free to post them in the comments, it would be greatly appreciated.</p>
]]></content:encoded>
			<wfw:commentRss>http://mquandt.com/blog/2009/12/important-additions-fixes-to-lpp-implementation/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Light Pre Pass in XNA: Basic Implementation</title>
		<link>http://mquandt.com/blog/2009/12/light-pre-pass-in-xna-basic-implementation/</link>
		<comments>http://mquandt.com/blog/2009/12/light-pre-pass-in-xna-basic-implementation/#comments</comments>
		<pubDate>Tue, 01 Dec 2009 13:43:33 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[DirectX]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Xbox 360]]></category>
		<category><![CDATA[XNA]]></category>
		<category><![CDATA[light pre pass]]></category>
		<category><![CDATA[tutorials]]></category>

		<guid isPermaLink="false">http://mquandt.com/blog/?p=60</guid>
		<description><![CDATA[NOTE: This article is now obsolete. An up-to-date sample and article can be found at http://mquandt.com/blog/2010/03/light-pre-pass-round-2/ In this part I will cover how to implement the basic form of the Light Pre Pass renderer, with support for point lights, and the basic Blinn-Phong shader, including Albedo texture support. As this article is fairly advanced in &#8230; <a href="http://mquandt.com/blog/2009/12/light-pre-pass-in-xna-basic-implementation/">Read more <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><strong>NOTE: This article is now obsolete. An up-to-date sample and article can be found at <a href="http://mquandt.com/blog/2010/03/light-pre-pass-round-2/">http://mquandt.com/blog/2010/03/light-pre-pass-round-2/</a></strong></p>
<p>In this part I will cover how to implement the basic form of the Light Pre Pass renderer, with support for point lights, and the basic Blinn-Phong shader, including Albedo texture support.</p>
<p>As this article is fairly advanced in nature, I have to make certain assumptions about my audience, so that I do not spend half my time explaining basics. Firstly, you should have an understanding of basic concepts such as Cameras, Fullscreen Quads (including how to render one) and rendering a mesh with custom effects.</p>
<p>This pretty much means that as long as you have done some 3D work before, you should be fine. It would be best if you also knew XNA, as I will be using that to write this implementation, however as long as you can translate from C# and get the basic idea, that should be enough.</p>
<p>As you can see from these requirements, this article is not aimed at beginners, and if you are looking for tutorials on how to get started with XNA for 3D development, I would recommend you visit some great sites such as:</p>
<ul>
<li><a href="http://creators.xna.com">http://creators.xna.com</a></li>
<li><a href="http://www.thehazymind.com">http://www.thehazymind.com</a></li>
<li><a href="http://xna-uk.net/blogs/randomchaos/">http://xna-uk.net/blogs/randomchaos/</a></li>
</ul>
<p>Those sites will help you get started with XNA, and once you are familiar and comfortable with the concepts behind 3D graphics, you can return here to learn an advanced renderer implementation.</p>
<p>My focus in this article will be on the implementation of the renderer, as a result, I will not be referring to the implementation of cameras or scene graphs.</p>
<p>Now that the housekeeping is out of the way, we can begin.</p>
<p><span id="more-60"></span></p>
<h3>The Renderer in C#</h3>
<p>Light Pre Pass (LPP), or Deferred Lighting, operates in 3 stages.</p>
<ol>
<li>Depth + Normals Rendering</li>
<li>Light Rendering</li>
<li>Materials Rendering</li>
</ol>
<p>These 3 stages accumulate information into render targets, which are used by the next stage, until the Materials stage produces the final image. So the first thing we must do, is set up at least the following Render Targets:</p>
<ul>
<li>Depth (SurfaceFormat.Single)</li>
<li>Normals (SurfaceFormat.Bgra1010102)</li>
<li>Lights (SurfaceFormat.Color)</li>
</ul>
<pre class="brush: csharp;">depth = new RenderTarget2D(gfx, width, height, 1, SurfaceFormat.Single, RenderTargetUsage.DiscardContents);
normals = new RenderTarget2D(gfx, width, height, 1, SurfaceFormat.Bgra1010102, RenderTargetUsage.DiscardContents);
light = new RenderTarget2D(gfx, width, height, 1, SurfaceFormat.Color, RenderTargetUsage.DiscardContents);
final = new RenderTarget2D(gfx, width, height, 1, SurfaceFormat.Color, RenderTargetUsage.DiscardContents);</pre>
<p>We use Bgra1010102 for storage of normals because we want maximum precision for the 3 channels we are using. The closest format that provides 32bits of depth and 3 channels is 1010102, where there are 10 bits for the 3 channels we care about, giving greater precision over the 8 bits in a normal A8R8G8B8 (or Color) surface format.</p>
<p>The Materials, or final pass can be rendered directly to the Backbuffer, or to a Render Target, this depends on your needs, and is completely up to you. I have provided suggested SurfaceFormats above, however you can feel free to use your own, however note that the shaders I provide may not work [correctly] with your chosen format.</p>
<h3>Depth + Normals</h3>
<p>The first stage of the renderer, requires you to render the Depth and Normal values for each pixel to the screen. You can optionally render the position directly, however many post processing techniques use depth information, so why not render it now to re-use later.</p>
<p>First we must setup the render targets on our device, easily done with two lines of code:</p>
<pre class="brush: csharp;">gfx.SetRenderTarget(0, depth);
gfx.SetRenderTarget(1, normals);</pre>
<p>For those who have not worked with multiple render targets before, the number in the above code indicates the render target index, and allows you to un-set and resolve the render target later.</p>
<p>Now you must first clear the render targets. As we are using multiple render targets, a simple call to GraphicsDevice.Clear will not suffice, instead we simply render a fullscreen quad using a cheap shader to write out the clear colours to the render targets.</p>
<pre class="brush: cpp;">struct VS_OUT
{
    float4 Position        : POSITION;
};

VS_OUT vs_main(float3 position : POSITION)
{
    VS_OUT output = (VS_OUT)0;
    output.Position = float4(position, 1);

    return output;
}

struct PS_OUT
{
    float4 Depth : COLOR0;
    float4 Normals : COLOR1;
};

PS_OUT ps_main()
{
    PS_OUT output = (PS_OUT)0;

    output.Depth = 1.0f;

    output.Normals = float4(0, 0, 0, 1);

    return output;
}</pre>
<p>Next you render the objects, using a special shader that writes the Depth and Normals to the two render targets. If you intend to implement Normal Mapping, or a similar technique, this is where you would calculate and combine the Normals. For the purposes of this article, only the basic per-vertex normals will be stored here.</p>
<p>One thing I had to do, was ensure a couple of render states were set correctly, specifically DepthBufferEnable and DepthBufferWriteEnable. Ensure both of these are set to true before continuing.</p>
<p>The Depth and Normals shader is quite simple. First the object is transformed as it would normally be when rendering, and then the Z and W values from the transformed position are passed to the pixel shader, alongside the Normal.</p>
<pre class="brush: cpp;">struct VS_IN
{
    float4 Position   : POSITION;
    float4 Normal     : NORMAL0;
};

struct VS_OUT
{
    float4 Position   : POSITION;
    float4 Depth      : TEXCOORD0;
    float4 Normal     : TEXCOORD1;
};

VS_OUT depthNorm_VS(VS_IN input)
{
    VS_OUT output = (VS_OUT)0;

    float4x4 wvp = mul(World, ViewProjection);

    output.Position = mul(input.Position, wvp);

    output.Depth.xy = output.Position.zw;

    output.Normal = mul(World, input.Normal);

    return output;
}</pre>
<p>If you look at your render targets, you may see a white image for the depth buffer, this is normal, as the differences in depth between most points on an object are miniscule, and close to 1. Your normals buffer however should look something like this:</p>
<p><a href="http://mquandt.com/blog/wp-content/uploads/2009/12/normals.png"><img style="display: inline; border-width: 0px;" title="normals" src="http://mquandt.com/blog/wp-content/uploads/2009/12/normals_thumb.png" border="0" alt="normals" width="244" height="139" /></a></p>
<p>Inside the pixel shader, the Z value is divided by the W value to get the depth, and that is written to the first render target. Then the Normal is normalised and shifted from a range of [-1, 1] to [0, 1].</p>
<pre class="brush: cpp;">struct PS_OUT
{
    float4 Depth : COLOR0;
    float4 Normals : COLOR1;
};

PS_OUT depthNorm_PS(float4 depth : TEXCOORD0, float4 normal : TEXCOORD1)
{
    PS_OUT output = (PS_OUT)0;

    output.Depth = depth.x / depth.y;

    output.Normals.rgb = 0.5f * (normalize(normal) + 1.0f);

    // Set alpha for both Depth and Normals to 1 (for some reason its required)
    output.Depth.a = 1.0f;
    output.Normals.a = 1.0f;

    return output;
}</pre>
<p>Now that we have our Depth and Normal values stored in the render targets, we can resolve and get their respective textures so that the lights can be rendered using this data. This is quite simple in XNA, just set the render targets on the graphics device to either another render target, or null. In this case, we can set RT0 to the light buffer, and set RT1 to null.</p>
<pre class="brush: csharp;">gfx.SetRenderTarget(0, light);
gfx.SetRenderTarget(1, null);
depthImage = depth.GetTexture();
normImage = normals.GetTexture();</pre>
<p>Be sure to clear the light buffer to TransparentBlack, and then we can move on to rendering the lights.</p>
<p>In this first tutorial, I will implement point lights only. Check back for future tutorials about implementing other types of lights, like Directional Lights, etc.</p>
<p>Rendering the light stage is a little bit more complicated than the Depth + Normals stage. This time around, a number of Render States must be set in the beginning, and even more for each light based on the position of the camera.</p>
<h4>Render States</h4>
<p>The following render states must be set when drawing the lights, to take advantage of alpha blending for blending multiple overlapping lights.</p>
<pre class="brush: csharp;">gfx.RenderState.AlphaBlendEnable = true;
gfx.RenderState.SeparateAlphaBlendEnabled = false;
gfx.RenderState.AlphaBlendOperation = BlendFunction.Add;
gfx.RenderState.SourceBlend = Blend.One;
gfx.RenderState.DestinationBlend = Blend.One;
gfx.RenderState.DepthBufferEnable = false;
gfx.RenderState.DepthBufferWriteEnable = false;</pre>
<p>Here we are disabling the Z-culling feature of the graphics card so that overlapping lights can be drawn, as well as enabling Alpha Blending over all channels of the render target so that the process of combining overlapping lights will be handled by hardware automatically. We also ensure that no modifications to the destination or source values are made during the blending stage, and that Additive blending is used. (Remember that lighting equations add multiple lights together)</p>
<p>Now you run through each light and set the CullMode render state based on where the camera frustum is located. If the frustum is inside or overlaps the light bounding volume (in this case a sphere), the CullMode needs to be set to CullClockwiseFace. CullCounterClockwiseFace should be set if the frustum is completely outside the light bounding volume. Remember to also ensure that the CullMode is set to CullCounterClockwiseFace after all of the lights have been rendered.</p>
<p>In the sample code, I use a Mesh to easily load and store the light volume, which for a Point Light, would be a sphere. A scaling matrix allows for the attenuation to be changed, so be sure to update any matrices as needed.</p>
<p>Some notes about the next code sample:</p>
<ul>
<li>cmanager is my CameraManager, it is used here to set the ViewProjection and InverseViewProjection matrices, which are required to transform the Depth back into a position for lighting.</li>
<li>caller is the Renderer class, which coordinates rendering each stage, as well as setting up and resolving the appropriate buffers.</li>
</ul>
<pre class="brush: csharp;">public void DrawLightDeferred(GraphicsDevice gfx, CameraManager cmanager, Renderer caller)
{
    shader.Begin();

    // Set Matrix params
    cmanager.ApplyCameraParameters(ref shader);
    shader.Parameters.GetParameterBySemantic("WORLD").SetValue(world);

    // Set Depth and Normals buffers
    shader.Parameters["Depth_Tex"].SetValue(caller.GetDepthImage());
    shader.Parameters["Normals_Tex"].SetValue(caller.GetNormalsImage());

    // Set lighting params
    shader.Parameters["LightPos"].SetValue(_pos);
    shader.Parameters["Attenuation"].SetValue(_attenuation);
    shader.Parameters["SpecPower"].SetValue(SpecularPower);
    shader.Parameters["LightColor"].SetValue(LightColor.ToVector4());

    for (int j = 0; j &lt; lightMesh.Meshes.Count; j++)
    {
        gfx.Indices = lightMesh.Meshes[j].IndexBuffer;

        for (int k = 0; k &lt; lightMesh.Meshes[j].MeshParts.Count; k++)
        {
            for (int i = 0; i &lt; shader.CurrentTechnique.Passes.Count; i++)
            {
                EffectPass pass = shader.CurrentTechnique.Passes[i];
                pass.Begin();

                gfx.VertexDeclaration = lightMesh.Meshes[j].MeshParts[k].VertexDeclaration;

                gfx.Vertices[0].SetSource(lightMesh.Meshes[j].VertexBuffer,
                    lightMesh.Meshes[j].MeshParts[k].StreamOffset,
                    lightMesh.Meshes[j].MeshParts[k].VertexStride);

                gfx.DrawIndexedPrimitives(PrimitiveType.TriangleList,
                    lightMesh.Meshes[j].MeshParts[k].BaseVertex,
                    lightMesh.Meshes[j].MeshParts[k].StartIndex,
                    lightMesh.Meshes[j].MeshParts[k].NumVertices,
                    lightMesh.Meshes[j].MeshParts[k].StartIndex,
                    lightMesh.Meshes[j].MeshParts[k].PrimitiveCount);

                pass.End();
            }
        }
    }
    shader.End();
}</pre>
<p>Now I need to run through some helper methods I use in the upcoming point light shader. These methods handle transforming a position from Post Projection space, to Screen space, as well as calculating the half pixel offset required by DX9.</p>
<pre class="brush: cpp;">float2 postProjToScreen(float4 position)
{
    float2 screenPos = position.xy / position.w;
    return (0.5f * (float2(screenPos.x, -screenPos.y) + 1));
}

float2 halfPixel()
{
    return -(0.5f / float2(fViewportWidth, fViewportHeight));
}</pre>
<p>These are simple enough, and more importantly, *just work*.</p>
<p>Now for the point light shader. Here the light volume is transformed as needed in a really simple vertex shader:</p>
<pre class="brush: cpp;">struct VS_OUT
{
    float4 Position            : POSITION;
    float4 LightPosition    : TEXCOORD0;
};

VS_OUT vs_main(float4 inPos : POSITION)
{
    VS_OUT output = (VS_OUT)0;

    float4x4 wvp = mul(World, ViewProjection);

    output.Position = mul(inPos, wvp);
    output.LightPosition = output.Position;

    return output;
}</pre>
<p>The following variables are also passed to the shader for lighting calculations:</p>
<pre class="brush: cpp;">float3 LightPos;
float Attenuation;
float SpecPower;
float4 LightColor;
float3 CamPos : VIEWPOSITION;
float3 EyeDepthRay;</pre>
<p>The key code comes in the pixel shader. The first thing needed is to transform the position of the pixel from post projection space to screen space. This is handled by the helper method I mentioned earlier. Then the half pixel offset is deducted from the screen space position, so that the values read from the Depth and Normal buffers are correct.</p>
<pre class="brush: cpp;">// Transform from post-projection to texcoords
float2 screenPos = postProjToScreen(projPos);
// DX9 half pixel offset
float2 texCoord = screenPos - halfPixel();

float depth = tex2D(depthSampler, texCoord);</pre>
<p>Next, read the depth from the Depth buffer, and if the value is not less than 1, we simply write a value of 0 for this pixel, as there is no depth information at that point, and nothing to light. If there is however, the lighting can be calculated for that point.</p>
<pre class="brush: cpp;">// Reconstruct position from screen space + depth
float4 position;
position.x = texCoord.x * 2 - 1;
position.y = (1 - texCoord.y) * 2 - 1;
position.z = depth;
position.w = 1.0f;
position = mul(position, InvViewProjection);
position.xyz /= position.w;</pre>
<p>For more information on how to reconstruct a position based on a depth value, read <a href="http://mynameismjp.wordpress.com/2009/03/10/reconstructing-position-from-depth/">this</a>. There are also alternative, and improved methods listed there, which can be used depending on your needs.</p>
<p>Next the normal is acquired from the normal buffer, and restored to the [-1, 1] range so that it can be correctly used in the lighting calculations.</p>
<pre class="brush: cpp;">// Restore Normal
float3 normal = tex2D(normSampler, texCoord);
normal = normalize(2.0f * normal - 1.0f);</pre>
<p>Now the lighting can begin. There are two key elements that need to be calculated for our light buffer: N.L and Attenuation. N.L is the basic element in every lighting equation, and simply consists of the dot product between the Normal and the Light Direction.</p>
<p>Attenuation is calculated by simply determining the ratio of distance to light over maximum attenuation, this is then flipped so that 0 is the furthest point from the light. Here I also pre-combine the attenuation and the N.L value. You can of course combine these later when writing out the buffer, ultimately it gives the same result.</p>
<pre class="brush: cpp;">// Attenuation Calcs
float3 lDir = LightPos - position;
float atten = saturate(1 - dot(lDir/Attenuation, lDir/Attenuation));
lDir = normalize(lDir);

// N.L
float nl = dot(normal, lDir) * atten;</pre>
<p>Next we calculate the specular value. As we are using the Blinn-Phong lighting equation later on, the Half Vector is used instead of the reflection Vector, which ends up being a cheaper calculation for us. (Negligible for most modern systems – but visual difference is imperceptible)</p>
<p>For the purposes of this article, I will only include the code from the Blinn-Phong variant, however in the downloadable sample, I provide both methods that can be toggled with a boolean. (Change the technique to change the method)</p>
<p>Remember that this only affects the specular value, so do not worry that this will restrict you to the Blinn-Phong (or just Phong) lighting model.</p>
<pre class="brush: cpp;">float3 halfDir = normalize(lDir + camDir);
spec = pow(saturate(dot(normal, halfDir)), SpecPower);</pre>
<p>Finally we generate the buffer and this is where we combine the light colour with the calculated N.L and Attenuation values.</p>
<pre class="brush: cpp;">return float4(LightColor.r, LightColor.g, LightColor.b, spec) * nl;</pre>
<p>You should get something that looks like this: (Note that due to transparency this may look weird, however the essential part to note is the lights making up the shape of the model)</p>
<p><a href="http://mquandt.com/blog/wp-content/uploads/2009/12/lights.png"><img style="display: inline; border-width: 0px;" title="lights" src="http://mquandt.com/blog/wp-content/uploads/2009/12/lights_thumb.png" border="0" alt="lights" width="244" height="139" /></a></p>
<p>Now we are entering the home stretch. All that is left to render now is the materials for each object. This is simply a matter of rendering each object again, and using the Light buffer to shade the object. Here is also where the material-flexibility of LPP comes into play, as each object uses its own shader.</p>
<p>To prepare for this stage, simple resolve the light buffer by setting either the backbuffer (null) or a “Final Image” render target as RT0. Then you can get the light texture, and provide it so the objects can use it when rendering.</p>
<p>This is the pixel shader:</p>
<pre class="brush: cpp;">float2 scrCoord = postProjToScreen(input.ScrCoord) - halfPixel();

float4 light = tex2D(lightSampler, scrCoord);

float3 texCol = tex2D(texSampler, input.TexCoord);

float3 lighting = saturate(AmbientLight + (light.rgb * texCol) + light.aaa);

return float4(lighting, 1);</pre>
<p>Here I adjust by the half pixel offset and transform from post projection to screen space inside the vertex shader, so those calculations are as before, however I pass the corrected Texture Coordinate to the pixel shader.</p>
<p>As this material is a Blinn-Phong material, it is a rather simple equation. The “Sum of light colour multiplied by N.L and attenuation” is handled by the Alpha Blending and light shaders, so that simply needs to be multiplied by the texture (Albedo) colour, which is then added to the ambient light term and specular term to complete the lighting equation.</p>
<p>Finally this is done, you now have either a backbuffer, or render target filled with a lit scene.</p>
<p><a href="http://mquandt.com/blog/wp-content/uploads/2009/12/final.png"><img style="display: inline; border-width: 0px;" title="final" src="http://mquandt.com/blog/wp-content/uploads/2009/12/final_thumb.png" border="0" alt="final" width="244" height="139" /></a></p>
<p>There are many other materials which can be adapted to use the light buffer, and there is also a modification that can be done to the light buffer and final material shaders to allow for a material specular value, however I will leave those to future articles.</p>
<p>I hope this has been informative, and if you have any questions, please post them in the comments. Also be sure to check back for new tutorials covering different light types, materials, and other additions. I hope to get shadows implemented into the system, and also outline combining this with a forward renderer to allow for transparent objects and particles.</p>
<p>The screenshots in this post use 1000 point lights arranged in a 10x10x10 cube around the model.</p>
]]></content:encoded>
			<wfw:commentRss>http://mquandt.com/blog/2009/12/light-pre-pass-in-xna-basic-implementation/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Light Pre Pass Implementation Ready</title>
		<link>http://mquandt.com/blog/2009/11/lpp-ready/</link>
		<comments>http://mquandt.com/blog/2009/11/lpp-ready/#comments</comments>
		<pubDate>Mon, 16 Nov 2009 14:50:33 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[DirectX]]></category>
		<category><![CDATA[XNA]]></category>
		<category><![CDATA[light pre pass]]></category>
		<category><![CDATA[tutorials]]></category>

		<guid isPermaLink="false">http://mquandt.com/blog/2009/11/lpp-ready/</guid>
		<description><![CDATA[&#160; As you can see, it is rendering correctly, and now I can begin writing about the implementation. Just have to clean some code, maybe improve one or two things. I hope to begin the article series (the previous entry was an intro) after my final exam on friday.]]></description>
			<content:encoded><![CDATA[<p>&#160;<a href="http://mquandt.com/blog/wp-content/uploads/2009/11/lpp_test1.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Light Pre Pass" border="0" alt="Light Pre Pass" src="http://mquandt.com/blog/wp-content/uploads/2009/11/lpp_test1_thumb.png" width="644" height="378" /></a>
</p>
<p>As you can see, it is rendering correctly, and now I can begin writing about the implementation.</p>
<p>Just have to clean some code, maybe improve one or two things. I hope to begin the article series (the previous entry was an intro) after my final exam on friday.</p>
]]></content:encoded>
			<wfw:commentRss>http://mquandt.com/blog/2009/11/lpp-ready/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>

