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.tsdescribes a cube map as sixCubeFaces: 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,acrossfor its columns,downfor its rows).optics/eac.tsreads it:cubeSamplestakes 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.cubeDirectionis its inverse.format/gopro/cube.tsbuilds a GoPro's cube from its track size alone: faces as tall as the track, bands of(width - 3 * height) / 2in the outer faces of each track, and the face order and frames measured on MAX2 frames by matching face edges.stitch/cubeRender.tsrenders 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.tspacks a cube-map frame into four-float slots (CUBE_LAYOUT), and the WebGPU adapter'screateCubeRendererdraws it, checked againstrenderCubeMapon 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.cubeis set for a cube map, withrecording.lensesandimagesempty, 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.tsrenders a GoPro recording's moment to a PNG for inspection (WEB360_GOPRO_PREVIEW).