Skip to content

ADR 0020: An equi-angular cube map is a picture of its own ​

Status: accepted (2026-10-20)

Context ​

ADR 0003's lens optics are fisheye-shaped. The GoPro MAX and MAX2 stitch their two lenses in the camera and store the sphere as an equi-angular cube map split across two video tracks (FORMAT-gopro.md). There is no lens to model and no seam for web360 to make; a frame only has to be read back out of the cube, apart from the narrow band where the camera's own seam is stored twice.

Decision ​

  • model/cube.ts describes a cube map as six CubeFaces: the texture and pixel rectangle the face is stored in, its logical size, the duplicated seam band at its middle (0 for none), and the cube frame it looks along (centre, across for its columns, down for its rows).
  • optics/eac.ts reads it: cubeSamples takes a direction to the face it leans toward most, through the equi-angular mapping (u = atan(across / centre) / (pi / 4)), to texture pixels; inside a seam band it returns both stored copies cross-faded linearly across the band, so the camera's seam step is smoothed. cubeDirection is its inverse.
  • format/gopro/cube.ts builds a GoPro's cube from its track size alone: faces as tall as the track, bands of (width - 3 * height) / 2 in the outer faces of each track, and the face order and frames measured on MAX2 frames by matching face edges.
  • stitch/cubeRender.ts renders a cube map to an equirectangular frame on the CPU, the reference a GPU pass is checked against, as the lens stitch has its own.
  • stitch/packCube.ts packs a cube-map frame into four-float slots (CUBE_LAYOUT), and the WebGPU adapter's createCubeRenderer draws it, checked against renderCubeMap on Dawn. It shares its full-screen pass (pass.ts) with the stitcher.
  • A recording opened by a vendor reader says which picture it is: OpenedRecording.cube is set for a cube map, with recording.lenses and images empty, and absent for lenses, which the lens stitch renders.

Consequences ​

  • A cube-map camera skips the colour work of the lens stitch: the camera already matched its lenses, and only the band's two copies are blended.
  • The original MAX takes the same order and frames as the MAX2, stated publicly; they are provisional, not measured on its frames.
  • stitch/goproPreview.test.ts renders a GoPro recording's moment to a PNG for inspection (WEB360_GOPRO_PREVIEW).

Released under the MIT License.