   Deferred Rendering (like in the nvidia demo)
  Hi,I successfully did some deferred rendering tests where I had the the world space coordinates for every pixel.Now I had a look at the demo by nvidia and they only have the depth for every pixel. Is anybody familiar with that approach? I had a look on the source code but got confused about the coordinate space in which the lighting is done.This is my code for preparing the render targets:VS_Output vertexShader(VS_Input input){VS_Output output;output.pos  = mul(input.pos, g_worldViewProj);output.tex  = input.tex;output.transformedPos  = mul(input.pos, g_worldViewProj);output.transformedNorm = normalize(mul(float4(input.norm, 0.0f), /*I AM NOT SURE WHAT TO USE HERE*/));   return output;}PS_Output pixelShader(VS_Output input){PS_Output output;output.color = float4(tex2D(colorMap, input.tex).rgb, 1.0f);// convert normal to texture space [-1, +1] -> [0, 1]output.norm.xyz = input.transformedNorm * 0.5f + 0.5f;//depthoutput.depth = float4(input.transformedPos.z / input.transformedPos.w, 0.0f, 0.0f, 0.0f);return output;}Any idea what the normals should be transformed to?Then during the lighting something like this is done:float x = input.pos2.x;float y = input.pos2.y;float z = tex2D(gBuffer_depth, input.tex);float4 pos = mul(float4(x, y, z, 1.0f), g_viewProjInv);pos.xyz = pos.xyz / pos.www;pos.w = 1.0f;This confuses me the most. What does pos represent now?It would nice to discuss this with someone who already did something similar.   
  Hi,Nvidia stores the post-perspective space depth of the vertex.  When they render the depth to the gbuffer they multiply the vertex position by the world, view and projection matrices.  This is the vertex position in clip-space.  This value is passed to the fragment shader on a TEXCOORD semantic, which will not have perspecive division applied to it automatically.In the fragment shader that renders to the gbuffer the value In.pos2.z / In.pos2.w is rendered into the texture.  This takes the clip-space depth (z) and performs perspective division (w).When performing shading on the next pass the vertex shader just passes vertices and texture coordinates through.  This is because nvidia is always rendering screen-aligned quads (they use the scissor rectangle test, there is an article by fabio policarpo that explains the scissor test method, he tries to explain depth reconstruction but it is very strange how he does it).In the fragment shader that calculates shading the z/w value for this pixel is retrieved from the gbuffer.To reconstruct the world space position of the pixel using the depth the following is executed:float x = In.Position2.x;float y = In.Position2.y;float4 pos = mul(float4(x,y,z,1.0),invProj);pos.xyz /= pos.w;pos.w = 1;What is going on here is that the x and y coordinates in clip space are specified as the x and y coordinates of the reconstructed point, then the post-perspective space depth is specified as the point's depth.  This point is multiplied by the inverse projection matrix which will transform the point to view space.  However, the clip-space point has already had perspective division applied to it (obvious for z, I will explain why for x and y in a bit), so we must divide by a factor of 1/w.  That is not a typo, pos.w = 1/w (the original w that z was divided by), so dividing by 1/w is multiplying by w which will cancel out the perspective division.  pow.w is set to 1 in case further transformation is desired.We now have the pixel's position in view space, the inverse view matrix can now by used directly to transform the point to world space.  In the code you showed, pos would be in world space after the matrix multiply, but perspective divide still needs to be cancelled out.The code above only works to reconstruct points when you render screen-aligned quads.  This works great if you are rendering an entire quad to compute the shading or are using the scissor test.  However, if you want to render light volumes, rather than screen aligned quads a small change must be made to the code above:float x = In.pos2.x;float y = In.pos2.y;float4 pos = mul(float4(In.pos2.xy/In.pos2.w,z,1.0),invProj);pos.xyz /= pos.w;In this case we are rendering 3D geometry to the screen and reconstructing the world space geometry with the projected 3D geometry.  In this case we must divide the x and y components of the clip-space vertices by w to normalize them to [-1,1].  In the case of screen-aligned quads this is handled for us because we use an orthographic projection to render screen-aligned quads, w for an orthographic projection is always 1, so the division is done implicitly.I hope that explanation helps you understand what is involved when reconstructing the point from the depth.  If anything is unclear let me know.  Also, I referred to reconstructing the point in world space, view space might be better and is also easy to do.As far as where to store normals when doing deferred shading, view space is pretty convenient.  You can do bump mapping with deferred shading in view space as well as other effects.  When you render to the gbuffer in the fragment shader transform tangent space normals sampled from a bump map to view space and store that vector.  View space lighting is very easy as you always know the eye position in view space.  But other spaces are possible/could be better, this is just what comes to mind.Hope this helps, I have a simple sample of this if you are really stuck and need code.   ;  Thanks for the long explanation, very appreciated!With your help I was able to get the world position:float x = input.pos2.x;float y = input.pos2.y;float z = tex2D(gBuffer_depth, input.tex);float4 worldPos = mul(float4(x, y, z, 1.0f), g_projInv);worldPos.xyz /= worldPos.w;worldPos.w = 1.0f;worldPos = mul(worldPos, g_viewInv);//this is now the position of the pixel in world space!Now it is pretty much working the way I want it. You mention it might be better to reconstruct the position in view space. May I ask why? I am already quite pleased with the results. Saved me a rendertarget and quite some frames.   ;  Hi,I didn't have any reason the suggest doing lighting in view space over world space, world space is equally valid.  You just can't do tangent space bump mapping with deferred shading, so you have to transform your normals to a space other than tangent space.   ;  That is quite alright, I am already having my normals in another space right now.I omit the "worldPos = mul(worldPos, g_viewInv);" step now and instead multiply the light pos with the view matrix before I pass it to the shader. This gets the same lighting results and is slightly faster.But another thing is broken now and I can't figure out why.For my spot lights I do a cone-like attenuation in the shader like this:float x = input.pos2.x;float y = input.pos2.y;float z = tex2D(gBuffer_depth, input.tex);float4 pos = mul(float4(x, y, z, 1.0f), g_projInv);pos.xyz /= pos.w;pos.w = 1.0f;float3 lightVec = g_lightPos - pos;float3 lightDir  = normalize(lightVec);if (dot(-lightDir, g_lightDir) < g_lightTheta)return float4(0.0f, 0.0f, 0.0f, 0.0f);   else //do the lightingThis worked while I still had "pos" and "g_lightPos" in world space. I also multiply g_lightDir with the view matrix before passing it to the shader so shouldn't it be alright in theory?Maybe you can see the mistake I am making.EDIT:Maybe I should just stick to world space as am having all kinds of trouble when for example applying the shadow/spot-map.[Edited by - B_old on August 25, 2007 9:05:45 AM];  Hi,another small question. You explain how I can reconstruct the position for the screen aligned quad and the light volume case. But how do I get the right texture coordinates when using a light volume?   ;Quote:Original post by B_oldHi,another small question. You explain how I can reconstruct the position for the screen aligned quad and the light volume case. But how do I get the right texture coordinates when using a light volume?Thats a piece of cake.  Just store the screen-space position of your vertex in the vertex shader, then in your fragment shader apply perspective division and do the usual screen-coordinate/texture-coordinate conversion.float2 texPos = 0.5f * IN.position2D.xy / IN.position2D.w + float2(0.5f, 0.5f);texPos.y = 1.0f - texPos.y;;  Hi,The problem with the attenuation in view space could be that the g_lightDir might not be normalized after multiplying by the view matrix.  So the dot product might not actually be the angle between the vectors.Give that a try, I'd have to look at it more though.Regarding your post about texture coordinates:What MJP said will work (inverting the y coord isn't necessary with OpenGL, just so you know).Another approach that essentially does the same thing, just the API will take care of it for you is to use the WPOS register.  The WPOS register simply contains the pixel position in the range [0,0]x[w,h], where w and h are viewport width and height respectively.So the output struct from the vertex shader becomes:struct v2f {// Original membersspos : WPOS;Don't write to spos in the vertex shader, it will be filled in automatically.spos can be accessed in the fragment shader.  In DirectX I am not entirely certain if they coord increases from bottom to top or from top to bottom in screen space, you might need to reverse that, but I'm not sure.But WPOS essentially does what MJP is saying to do, but it applies the viewport transform to the result.One last note, WPOS is the Cg semantic, in HLSL it is called VPOS but it does the same thing.   ;  Hi and thanks for the input!I tried what MJP said, and it worked. Almost. The result is off by 1 or maybe 2 pixels. It is definitively visible by comparison.I had trouble with the brtnrdr approach though.It seems that you have to do it like this in d3d/hlsl:struct VS_Output_volume {    float4 pos   : Position;    float4 pos2  : TexCoord0;};struct PS_Input_volume {    float4 pos   : Position;float2 tex   : VPOS;    float4 pos2  : TexCoord0;};Does that make sense? It wouldn't compile otherwise.Anyway using the above tex directly in PS doesn't give the results I expected.Do I still have to transform in the PS?Thanks again for the help!   ;  Hi,The way you have the structs laid out is how you are supposed to do it in HLSL (I think in Cg you can specify it in the vertex shader output struct and just not write to it).  I guess the VPOS register is only available on PS3.0 hardware, so you need to be using hardware that supports PS3.0 and be compiling the shader as PS3.0.Does using VPOS give correct results or is it not working?MJP's method seems like it should work, explain what you are doing exactly, maybe there's something being done wrong.   