Reconstructing Position From Depth

Matt posted an excellent article about reconstructing position from depth. Check out his article here: http://mynameismjp.wordpress.com/2009/03/10/reconstructing-position-from-depth/ He has the following function to reconstruct View Space Position from Post Clip Space Position:
// Function for converting depth to view-space position
// in deferred pixel shader pass.  vTexCoord is a texture
// coordinate for a full-screen quad, such that x=0 is the
// left of the screen, and y=0 is the top of the screen.
float3 VSPositionFromDepth(float2 vTexCoord)
{
    // Get the depth value for this pixel
    float z = tex2D(DepthSampler, vTexCoord); 

    // Get x/w and y/w from the viewport position
    float x = vTexCoord.x * 2 - 1;
    float y = (1 - vTexCoord.y) * 2 - 1;
    float4 vProjectedPos = float4(x, y, z, 1.0f);

    // Transform by the inverse projection matrix
    float4 vPositionVS = mul(vProjectedPos, g_matInvProjection);  

    // Divide by w to get the view-space position
    return vPositionVS.xyz / vPositionVS.w;  
}
The basic idea is that if we have a matrix that transfoms from View Space to Clip Space, we just take the inverse of that matrix and multiply it with the clip space position we should be able to get back the view space position. But my biggest question was why did we need to divide-by-w (in view space) at the end? I thought the order is like this:
PosInClipSpace = PosInViewSpace * ProjMtx;
PosInPostClipSpace = PosInClipSpace / PosInClipSpace.w;
so, if we want to get back from PosInPostClipSpace to PosInViewSpace, we need to do this:
PosInClipSpace = PosInPostClipSpace * PosInClipSpace.w;
PosInViewSpace = PosInClipSpace * ProjMtx_INVERSE;
so, somehow we need to save the w in order to get back the position in View Space. Out of curiosity, I did the Inverse of Projection Matrix MANUALLY and work out the following:
PosInViewSpace0 = PosInPostClipSpace * ProjMtx_INVERSE;
PosInViewSpace = PosInViewSpace0 / PosInViewSpace0.w;
It turns out the MATH WORKS OUT! I can't see why this is happening logically, but mathematically it's correct! It's amazing, I learned a new thing today! My next question is, if I want to bring it to World Space instead of View Space, do I need 2 matrix multiplication steps such as the following:
PosInViewSpace0 = PosInPostClipSpace * ProjMtx_INVERSE;    // First Mtx Mult
PosInViewSpace = PosInViewSpace0 / PosInViewSpace0.w;
PosInWorldSpace= PosInViewSpace * ViewMtx_INVERSE;    // Second Mtx Mult
It turns out, I don't need that. I can just multiply with ViewProjMtx_INVERSE and divide-by-w at the end, i.e.:
PosInWorldSpace0 = PosInPostClipSpace * ViewProjMtx_INVERSE;
PosInWorldSpace = PosInWorldSpace0 / PosInWorldSpace0.w;
This works because if you pay attention to ViewMtx_INVERSE, the fourth column is actually (0, 0, 0, 1) which basically doesn't modify the w. That's why you can do divide-by-w at the end and still get the correct result!

Comments

Popular posts from this blog

World, View and Projection Matrix Internals

BASH: Reading Text File

GDC 2015 Links