Friday, September 24, 2010

Reconstructing View Space Position from Depth in OpenGL ES 2.0

There is a lot of information scattered around the Internet on this (some of which seems wrong). Here is some rough code for my solution to the problem. I only just got this working, so I hope it is correct... you have been warned!

First, I will describe the inputs:

  • winPos - Pixel position (from gl_FragCoord.xy).
  • winSize - Size of window in pixels.
  • depthSample - Raw depth value from the depth texture (should be in the range of [0, 1]).
  • nearFar - Distances of the near and far planes.
  • u_top, u_right - Top and right limits of the near plane.

For u_top and u_right, I derive it from my vertical field of view angle and aspect ratio (width / height) like so (C++):
    m_top = m_near * Math::tan(0.5f * m_verticalFov);
    m_right = m_top * m_display->aspectRatio();
Given all that, here is the GLSL function that will return the view space position for the given pixel position:
vec3 viewSpacePos(vec2 winPos, vec2 winSize, vec4 depthSample, vec2 nearFar)
{
    vec3 position;

    float depth = depthSample.x;
    position.z = -nearFar.x / (nearFar.y - (depth * (nearFar.y - nearFar.x))) * nearFar.y;

    position.x = (((winPos.x / winSize.x) * 2.0) - 1.0) * u_right;
    position.y = (((winPos.y / winSize.y) * 2.0) - 1.0) * u_top;

    float scale = -position.z / nearFar.x;
    position.x *= scale;
    position.y *= scale;

    return position;
}
Hope this helps someone out there! It might be best you try derive it yourself too, so you can debug it (if you ever need to)... :)

UPDATE: Made small correction to how scale was calculated. Oops!