Tangential distortion

How a decentered or tilted lens breaks radial symmetry — and how an iterative shader reconstructs the source coordinate.

Visible effect

Look for broken symmetry

A centred grid reveals what radial distortion cannot explain.

The lines do not bow with rotational symmetry. Instead, opposite sides lean in the same direction: the mapping has acquired an orientation.

Physics

When the lens groups do not share one axis

How lens decentering breaks rotational symmetry A centred lens keeps its mechanical and optical axes together. A shifted element moves the optical axis away from the mechanical axis and produces an oriented displacement field in the image.mechanical axisoptical axisdecentered elementoriented point displacement
Lens groups are assembled around a mechanical axis. Decentering or tilt separates it from the effective optical axis, so the mapping gains a direction instead of depending on radius alone.

An ideal centred objective is rotationally symmetric around its optical axis. Real elements can be shifted sideways or tilted during assembly. The effective optical axis then separates from the mechanical axis, and off-axis image points acquire a directional position error.

Mathematics

Two coefficients describe an oriented offset

Brown–Conrady adds a decentering term to an ideal normalized point. The coefficients p1 and p2 set the two components of the asymmetry:

These equations are a forward camera model: ideal point → distorted point. The live vector field shows that direction. The fragment shader needs the reverse question, distorted output point → source point, and solves it iteratively.

Shader

GLSL inverse mapping function

The playground compiles the complete function below. Nine fixed-point iterations are enough for the deliberately bounded interactive coefficient range.

tangentialSourceCoordinateGLSL
// WHAT: Find the source coordinate displaced by decentered-lens distortion.
// HOW: Evaluate the Brown–Conrady tangential offset repeatedly in
// aspect-correct space and subtract it from the requested destination point.
// WHY: The tangential model is defined forward, but rendering needs its inverse
// so every destination pixel receives exactly one sample.
vec2 tangentialSourceCoordinate(
  vec2 destinationUv01,
  vec2 centerUv01,
  vec2 tangential,
  float aspect
) {
  // Isotropic coordinates keep x and y coefficients physically comparable.
  vec2 scale = vec2(aspect, 1.0);
  vec2 distorted = (destinationUv01 - centerUv01) * scale;
  vec2 source = distorted;

  for (int iteration = 0; iteration < 9; iteration++) {
    float x = source.x;
    float y = source.y;
    float radiusSquared = dot(source, source);
    // p1 and p2 encode the two decentring directions of the lens system.
    vec2 offset = vec2(
      2.0 * tangential.x * x * y +
        tangential.y * (radiusSquared + 2.0 * x * x),
      tangential.x * (radiusSquared + 2.0 * y * y) +
        2.0 * tangential.y * x * y
    );
    // Fixed-point refinement estimates the source that maps to this output.
    source = distorted - offset;
  }

  // Convert the converged point back to normalized texture coordinates.
  return centerUv01 + source / scale;
}
Processing pipelineBoxes mark actual render-pass boundaries.
  1. Source texture
  2. Iterative coordinate remapOne texture read per output pixel
    • Iteratively invert the tangential displacement
    • Sample the source coordinate
  3. Display output

Why these steps are here

  1. Centre and scale. The optical centre becomes the origin, and the x coordinate is scaled by the render-target aspect ratio so equal distances remain circular.
  2. Evaluate the forward offset. Each iteration applies the same p1/p2 terms as the mathematical model.
  3. Correct the estimate. Subtracting the predicted offset from the known distorted coordinate converges on the source point without pushing pixels or leaving raster holes.
  4. Return to texture space. The function removes the aspect correction and restores the optical centre before the texture lookup.

No history buffer is required. Large coefficients can make fixed-point inversion unstable.

Notes

  • “Tangential” is the calibration-model name; it does not mean every point moves exactly along a circle tangent.
  • The polynomial approximates the image mapping rather than tracing the actual decentered glass.
  • Radial and tangential terms are commonly fitted together during camera calibration.
  • Coefficients are meaningful only with the coordinate normalization used by the calibration and shader.

References

OpenCV camera calibration documentation — defines radial and tangential camera-distortion models and their calibration coefficients.