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!

Sunday, August 29, 2010

Deferred Rendering Done!



Just a quick update - finally finished the deferred rendering system for Battle Balloons! Guerilla Games has a good presentation for Killzone 2 on the theory behind it - but mine is not as advanced. Not much to show as it's pretty much all under-the-hood at the moment. But this excites me because I no longer need to worry about how to limit the number of lights in the game - they can now be practically unlimited. I went with a fairly simple approach:
  1. the scene normals are rendered in RGB as-is (if it's good enough precision for Insomniac Games' Resistance 2, then it's good enough for me!),
  2. pixel world position is derived from the 2D screen co-ordinates and depth buffer value, and
  3. lighting happens in two stages: a spherical mesh is first rendered for each light onto the stencil buffer and the light shading is then calculated for each pixel not masked out by the stencil.
In the process of doing so I also removed all legacy, fixed-functionality OpenGL code. Everything is now pretty-much OpenGL ES v2.0 compliant. Now with this out of the way, it is on to adding networking support; the last, major, technical hurdle for this project! :)

Saturday, July 17, 2010

Approaching Feature-Complete...

I've been banging away at Battle Balloons in my spare time lately and here's the latest progress! I have most of the features I need now (but still quite a few more to add...). The code is starting to look a bit messy though, so it will just be clean-up work at this point. No more updates for awhile. :( Enjoy the video! You can also download the build (for Windows) and try it out if you want.