Skip to content

Camera Module

src/camera/ provides the view/projection plumbing that every subsystem (preprocess, renderer, controls, Three.js bridge) relies on. The module is intentionally small: a Camera interface, a concrete PerspectiveCamera + PerspectiveProjection, and a CameraAdapter for mirroring Three.js cameras.

Responsibilities

  • Supply stable view/projection matrices for GPU uniforms (column-major, WebGPU NDC).
  • Manage field-of-view, aspect ratio, and near/far plane math with PerspectiveProjection.
  • Expose convenient helpers (fitNearFar, resize, focal, lerp) so renderers and controls can adapt to scene bounds or viewport changes.
  • Provide world2view / buildProj utilities for tooling or custom cameras.
  • Offer CameraAdapter to reuse Three.js cameras inside preprocessing/sorting pipelines without rewriting math.

Components

Component Path Purpose
Camera interface perspective.ts Minimal contract used by renderer/preprocessor (view matrix, projection matrix, position, frustum planes).
PerspectiveProjection perspective.ts Stores fovx, fovy, znear, zfar, handles resize + interpolation + matrix generation.
PerspectiveCamera perspective.ts Concrete Camera implementation with positionV, rotationQ, near/far fitting, frustum extraction, caching-ready getters.
CameraAdapter CameraAdapter.ts Converts a THREE.PerspectiveCamera into the same view/projection/focal data expected by the preprocessing shaders.
Utilities index.ts Re-exports world2view, buildProj, and math helpers (deg2rad, focal2fov, fov2focal, VIEWPORT_Y_FLIP).

Data Flow

PerspectiveCamera ──view/proj�?Uniform buffer (renderer & preprocess)
PerspectiveProjection ──resize/focal/lerp�?camera settings UI / animation
CameraAdapter ──update(THREE.PerspectiveCamera)�?view/proj/focal for preprocess dispatch
world2view & buildProj ──utility hooks�?custom camera implementations

Highlights

  • gl-matrix under the hood: All math is backed by gl-matrix (vec3, quat, mat3, mat4) for predictable performance and memory layouts.
  • Right-handed, WebGPU friendly: View space looks down −Z; projection matrices map into WebGPU’s [0,1] depth range. VIEWPORT_Y_FLIP is exported when a stage requires flipping Y once (preprocess already compensates).
  • Near/far fitting: PerspectiveCamera.fitNearFar(aabb) computes a tight depth range around a bounding box (with a 1.5× far margin and 1:1000 near/far clamp) to maximise precision during preprocessing and rendering.
  • Frustum extraction: frustumPlanes() multiplies projection and view matrices and emits six normalized plane equations for culling.
  • Viewport aware: PerspectiveProjection.resize(viewport) keeps the horizontal/vertical FOV ratio consistent when the canvas size changes, so UI resizes do not distort the image.
  • Animation ready: PerspectiveProjection.lerp() and quaternion-based rotation make it easy to interpolate cameras for timelines or control systems.
  • Three.js bridge: CameraAdapter.update() copies Three’s matrices, applies the same Y-flip compensation used in preprocess, computes per-axis focal lengths, and exposes the same interface preprocess expects. This powers the three-integration demos without diverging from the core pipeline.

Integration Points

Subsystem Usage
Preprocess (GaussianPreprocessor) Needs view/projection matrices, focal lengths, and camera uniforms for projecting splats. Accepts either PerspectiveCamera or the CameraAdapter output.
Renderer (GaussianRenderer) Calls camera.viewMatrix() / projMatrix() every frame to fill camera uniform buffers before drawing.
Controls module Mutates positionV, rotationQ, or projection (via resize) and marks matrices dirty in the host app.
Three.js integration CameraAdapter mirrors PerspectiveCamera state so the core pipeline can run inside Three’s render loop.

Usage

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

const projection = new PerspectiveProjection(
  [canvas.width, canvas.height],
  [deg2rad(60), deg2rad(45)],
  0.1,
  1000,
);
const camera = new PerspectiveCamera(vec3.fromValues(0, 0, -1), quat.create(), projection);

// Match viewport changes
window.addEventListener('resize', () => {
  projection.resize([canvas.width, canvas.height]);
});

// Fit depth range to a point cloud
camera.fitNearFar(pointCloud.bbox);

// Upload to GPU
cameraUniforms.setData({
  view: camera.viewMatrix(),
  proj: camera.projMatrix(),
  position: camera.position(),
});

Using CameraAdapter with Three.js

const adapter = new CameraAdapter();
adapter.update(threeCamera, [canvas.width, canvas.height]);

preprocessor.dispatchModel({
  camera: adapter,
  viewport: [canvas.width, canvas.height],
  // ... other args
}, encoder);
  • Architecture – Math details, frustum derivations, and adapter nuances.
  • API Reference – Constructor signatures, resize helpers, and exported utilities.
  • Three Integration – Shows how CameraAdapter feeds the WebGPU bridge.