Skip to content

Universal Distortion Shader

James Sarrett edited this page Mar 29, 2017 · 9 revisions


The universal distortion shader is a GLSL implementation of the PanoTools lens distortion model. This means that anyone with Hugin and a wide enough camera can measure the distortion of a new HMD and use it with OpenHMD.


The shaders are only the distortion correction portion of the render pipeline. The vertex shader passes the first texture co-ordinate through unchanged and does the standard OpenGL MVP transform. The fragment shader warps the texture co-ords according to the lens distortion model. The expected usage is that the application will first render the Left and right eyes to separate textures with no distortion. Then each eye will be textured on a quad covering the appropriate region of the HMD. In order to use the shader, some uniforms need to be set.

  • tex2d warpTexture

    • The eye texture which will be distorted.
  • vec2 ViewportScale

    • Scale from texture co-ords to real world units
    • Usually eye_w, eye_h in meters
    • Typically constant for both eyes
  • vec2 LensCenter

    • Position of lens center in real world units
    • Usually near eye_w/2, eye_h/2 in meters
    • Measured from texture origin (lower left)
  • float WarpScale

    • Distortion overall scale in m
    • Usually ~eye_w/2
    • This sets the physical size of the distorted rendering
    • {e.g. max(LensCenter.x, ViewportScale.x - LensCenter.x)}
  • vec4 HmdWarpParam

    • Distortion coefficients
    • PanoTools model [a,b,c,d]
    • Usually d = 1 - (a + b + c)
  • vec3 aberr

    • Chromatic distortion post scaling
    • Each of R,G,B co-ords are multiplied by these terms to independently scale the final image channels

Measuring distortion Coefficients for a new HMD

More detail required, but the basic steps are:

  1. Find a camera with a wide enough FoV (fisheyes may be required). e.g. Canon EOS-M with a Rokinon 7.5mm and Conversion kit
  2. Calibrate the camera. I've found the best thing is several (3+) images from the same nodal point covering the FoV of the camera, with enough control points to cover most of the center image. If you have a rectilinear lens it might be enough to just do a straight-line calibration.
  3. Put up an undistorted test pattern covering the whole HMD screen. i.e. a checkerboard with large (~100px) squares
  4. Take a picture through the HMD lens of the test pattern. You want the camera entrance pupil in the same place as the eye would be. That is probably where one or both edges of the screen just line up with the lenses, and the lenses are centered in the frame, and the camera center is the viewport center.
  5. Undistort and project the picture cropped to a known FoV, just covering the lens as a rectilinear projection. e.g. 100 degrees on DK2. This will give you an ideal undistorted rectified image of the test target through the HMD lens
  6. Calibrate the HMD lens from the rectified image of just the lens. You may find it easier to just use 1 channel (e.g. green) to make choosing control points easier. (e.g. convert camera_unwarp_90.jpg -fx G camera_unwarp_90_g.jpg) I've found that the easiest thing is to just have 3 control points across each line on the checkerboard edges, one at each extreme and one in the middle.
  7. Use the a,b,c values from the calibration as the distortion coefficients (d=1-a-b-c).
You can’t perform that action at this time.