Skip to content

Camera Module API Reference

This reference tracks the real exports from src/camera/. All maths are based on gl-matrix (vec3, vec2, quat, mat3, mat4).

Exports

import {
  type Camera,
  PerspectiveCamera,
  PerspectiveProjection,
  CameraAdapter,
  world2view,
  buildProj,
  deg2rad,
  focal2fov,
  fov2focal,
  Aabb,
  VIEWPORT_Y_FLIP,
} from 'src/camera';

Interface: Camera

interface Camera {
  viewMatrix(): mat4;
  projMatrix(): mat4;
  position(): vec3;
  frustumPlanes(): {
    near: Float32Array;
    far: Float32Array;
    left: Float32Array;
    right: Float32Array;
    top: Float32Array;
    bottom: Float32Array;
  };
}

Any camera passed to preprocess or renderer must implement this interface. A few notes: - Matrices must be column-major and ready for GPU upload. - position() returns a clone (mutating the result has no effect on the camera). - frustumPlanes() returns normalized [A, B, C, D] planes suitable for distance tests.

Class: PerspectiveProjection

class PerspectiveProjection {
  constructor(
    viewport: vec2 | [number, number],
    fov: vec2 | [number, number], // radians [fovx, fovy]
    znear: number,
    zfar: number,
  );

  fovx: number;
  fovy: number;
  znear: number;
  zfar: number;

  clone(): PerspectiveProjection;
  resize(viewport: vec2 | [number, number]): void;
  projectionMatrix(): mat4;
  focal(viewport: vec2 | [number, number]): [number, number];
  lerp(other: PerspectiveProjection, t: number): PerspectiveProjection;
}

Behaviour

  • resize() preserves the original relationship between viewport aspect and FOV aspect via an internal fov2viewRatio.
  • projectionMatrix() is a thin wrapper over buildProj(znear, zfar, fovx, fovy) (WebGPU depth range [0, 1]).
  • focal() returns per-axis focal lengths in pixels (used by preprocess).
  • lerp() interpolates FOV and near/far planes for smooth camera animations.

Class: PerspectiveCamera

class PerspectiveCamera implements Camera {
  constructor(position: vec3, rotation: quat, projection: PerspectiveProjection);

  static default(): PerspectiveCamera;
  positionV: vec3;       // world-space position (use clones when assigning)
  rotationQ: quat;       // world->camera quaternion
  projection: PerspectiveProjection;

  fitNearFar(aabb: Aabb): void;
  viewMatrix(): mat4;
  projMatrix(): mat4;
  position(): vec3;
  frustumPlanes(): {
    near: Float32Array;
    far: Float32Array;
    left: Float32Array;
    right: Float32Array;
    top: Float32Array;
    bottom: Float32Array;
  };
}

Notes

  • fitNearFar(aabb) adjusts znear/zfar based on the distance between the camera and the AABB centre, enforcing a minimum ratio (zfar / 1000).
  • viewMatrix() converts rotationQ into a 3×3 matrix and calls world2view (world→camera transform).
  • frustumPlanes() multiplies projMatrix * viewMatrix and extracts Gribb–Hartmann planes; normals are normalized.
  • static default() creates a camera at (0,0,-1) with 45° FOV and [0.1, 100] depth range.

Class: CameraAdapter

Allows Three.js cameras to drive the core pipeline.

class CameraAdapter implements Camera {
  update(camera: THREE.PerspectiveCamera, viewport: [number, number]): void;
  viewMatrix(): mat4;
  projMatrix(): mat4;
  position(): Float32Array;
  frustumPlanes(): Float32Array; // placeholder (24 values)
  projection: { focal(viewport?: [number, number]): [number, number] };
  transposeRotation: boolean;
  flipProjY: boolean;
  flipProjX: boolean;
}

Behaviour

  • update() copies Three’s matrices, premultiplies by diag(-1, 1, -1, 1) so view/projection match the core convention, compensates for the Y flip performed during preprocess packing, and computes per-axis focal lengths.
  • After calling update, the adapter satisfies the Camera interface and can be passed directly to dispatchModel or renderer code.

Functions

world2view(R_wc: mat3, C: vec3): mat4

Builds a world→camera transform from a rotation matrix (world→camera) and camera position.

buildProj(znear: number, zfar: number, fovx: number, fovy: number): mat4

Returns a column-major perspective matrix compatible with WebGPU’s clip-space conventions.

Math helpers (re-exported)

  • deg2rad(degrees: number): number
  • fov2focal(fovRadians: number, pixels: number): number
  • focal2fov(focalPixels: number, pixels: number): number
  • Aabb (axis-aligned bounding box utility used by fitNearFar).
  • VIEWPORT_Y_FLIP �?mat4 constant that multiplies Y by �? (used where a single flip is required).

Example

import { PerspectiveCamera, PerspectiveProjection, deg2rad } from 'src/camera';

const projection = new PerspectiveProjection(
  [1920, 1080],
  [deg2rad(65), deg2rad(45)],
  0.1,
  500,
);
const camera = new PerspectiveCamera(vec3.fromValues(0, 2, -4), quat.create(), projection);
camera.fitNearFar(pointCloud.bbox);

const view = camera.viewMatrix();
const proj = camera.projMatrix();
const planes = camera.frustumPlanes();

Using Three.js:

const adapter = new CameraAdapter();
adapter.update(threeCamera, [canvas.width, canvas.height]);
preprocessor.dispatchModel({ camera: adapter, viewport: [canvas.width, canvas.height], /* ... */ }, encoder);