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.