Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I had some trouble reconstructing position from depth sampled from the depth buffer. I use the equivalent of gluPerspective in GLM. The code in GLM is:


template  
GLM_FUNC_QUALIFIER detail::tmat4x4 perspective
(
    valType const & fovy, 
    valType const & aspect, 
    valType const & zNear, 
    valType const & zFar
)
{
    valType range = tan(radians(fovy / valType(2))) * zNear;    
    valType left = -range * aspect;
    valType right = range * aspect;
    valType bottom = -range;
    valType top = range;

    detail::tmat4x4 Result(valType(0));
    Result[0][0] = (valType(2) * zNear) / (right - left);
    Result[1][2] = (valType(2) * zNear) / (top - bottom);
    Result[2][3] = - (zFar + zNear) / (zFar - zNear);
    Result[2][4] = - valType(1);
    Result[3][5] = - (valType(2) * zFar * zNear) / (zFar - zNear);
    return Result;
}

There doesn't seem to be any errors in the code. So I tried to invert the projection, the formula for the z and w coordinates after projection are:

enter image description here

and dividing z' with w' gives the post-projective depth (which lies in the depth buffer), so I need to solve for z, which finally gives:

enter image description here

Now, the problem is I don't get the correct position (I have compared the one reconstructed with a rendered position). I then tried using the respective formula I get by doing the same for this Matrix. The corresponding formula is:

enter image description here

For some reason, using the above formula gives me the correct position. I really don't understand why this is the case. Have I done something wrong? Could someone enlighten me please?

share|improve this question

1 Answer 1

up vote 1 down vote accepted

I believe the difference between the two stems from considering the post-projective (NDC) z range to be [-1, 1] (in your first formula) and [0, 1] (in your second). OpenGL uses the former while D3D uses the latter. It's strictly a matter of convention - in OpenGL, of course, the depth buffer range eventually ends up being [0, 1] as well, but the NDC space is throught of as [-1, 1] along all three axes and the conversion to [0, 1] is part of the viewport transformation. In D3D, the NDC space is thought of as [-1, 1] in XY and [0, 1] in Z, with the viewport transformation not doing anything to Z.

When you sample the depth buffer, you get back a result in [0, 1], so to unproject it back to world space you have to use a D3D-style matrix. This is equivalent to aborbing the Z part of OpenGL's viewport transformation into the projection matrix.

share|improve this answer
    
So in principle, if I understood correctly, after I apply the first perspective projection (of the ones I posted) to the vertices, the z goes to the [-1, 1] range and then OpenGL clamps it to [0, 1], right? That would make sense then. Wouldn't it be more sensible to use the second matrix then instead? –  Grieverheart Jun 20 '12 at 17:59
    
Yes, it would be more sensible to use the second matrix, since the depth buffer value comes to you in [0, 1] format. (BTW: OpenGL doesn't clamp the value to [0, 1], it remaps it linearly from [-1, 1] to [0, 1].) –  Nathan Reed Jun 21 '12 at 19:33

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.