Camera模块
src/camera/ 提供了每个子系统(预处理、渲染器、控制、Three.js 桥接)所依赖的视图/投影基础架构。该模块特意保持精简:一个 Camera 接口、具体的 PerspectiveCamera + PerspectiveProjection,以及用于镜像 Three.js 相机的 CameraAdapter。
职责
- 为 GPU Uniforms 提供稳定的视图/投影矩阵(列主序,WebGPU NDC)。
- 使用
PerspectiveProjection 管理视场 (FOV)、宽高比和近/远平面数学运算。
- 暴露便捷的辅助函数 (
fitNearFar, resize, focal, lerp),以便渲染器和控制器可以适应场景边界或视口变化。
- 为工具或自定义相机提供
world2view / buildProj 实用程序。
- 提供
CameraAdapter 以在预处理/排序管线中重用 Three.js 相机,而无需重写数学逻辑。
组件
| 组件 |
路径 |
目的 |
Camera 接口 |
perspective.ts |
渲染器/预处理器使用的最小契约(视图矩阵、投影矩阵、位置、视锥体平面)。 |
PerspectiveProjection |
perspective.ts |
存储 fovx, fovy, znear, zfar,处理大小调整 + 插值 + 矩阵生成。 |
PerspectiveCamera |
perspective.ts |
具体的 Camera 实现,具有 positionV, rotationQ,近/远拟合,视锥体提取,以及支持缓存的 Getters。 |
CameraAdapter |
CameraAdapter.ts |
将 THREE.PerspectiveCamera 转换为预处理着色器所需的相同视图/投影/焦距数据。 |
| 实用工具 |
index.ts |
重新导出 world2view, buildProj, 以及数学辅助函数 (deg2rad, focal2fov, fov2focal, VIEWPORT_Y_FLIP)。 |
数据流
PerspectiveCamera ──view/proj→ Uniform 缓冲 (渲染器 & 预处理)
PerspectiveProjection ──resize/focal/lerp→ 相机设置 UI / 动画
CameraAdapter ──update(THREE.PerspectiveCamera)→ 用于预处理调度的 view/proj/focal
world2view & buildProj ──utility hooks→ 自定义相机实现
亮点
- 底层使用 gl-matrix: 所有数学运算均由
gl-matrix (vec3, quat, mat3, mat4) 支持,以实现可预测的性能和内存布局。
- 右手坐标系,WebGPU 友好: 视图空间看向 -Z;投影矩阵映射到 WebGPU 的
[0,1] 深度范围。当某个阶段需要翻转一次 Y 时(预处理已进行补偿),会导出 VIEWPORT_Y_FLIP。
- 近/远拟合:
PerspectiveCamera.fitNearFar(aabb) 计算包围盒周围的紧密深度范围(具有 1.5 倍远距余量和 1:1000 近/远钳位),以最大化预处理和渲染期间的精度。
- 视锥体提取:
frustumPlanes() 乘投影和视图矩阵,并发射六个归一化的平面方程用于剔除。
- 视口感知:
PerspectiveProjection.resize(viewport) 在画布大小更改时保持水平/垂直 FOV 比率一致,因此 UI 大小调整不会使图像变形。
- 动画就绪:
PerspectiveProjection.lerp() 和基于四元数的旋转使得为时间轴或控制系统插值相机变得容易。
- Three.js 桥接:
CameraAdapter.update() 复制 Three 的矩阵,应用预处理中使用的相同 Y 翻转补偿,计算各轴焦距,并暴露预处理期望的相同接口。这为 three-integration 演示提供了动力,而不会偏离核心管线。
集成点
| 子系统 |
用法 |
预处理 (GaussianPreprocessor) |
需要视图/投影矩阵、焦距和相机 Uniforms 来投影 Splat。接受 PerspectiveCamera 或 CameraAdapter 的输出。 |
渲染器 (GaussianRenderer) |
每帧调用 camera.viewMatrix() / projMatrix() 以在绘制前填充相机 Uniform 缓冲。 |
| 控制模块 |
变异 positionV, rotationQ, 或 projection (通过 resize) 并在宿主应用中标记矩阵为脏 (dirty)。 |
| Three.js 集成 |
CameraAdapter 镜像 PerspectiveCamera 状态,以便核心管线可以在 Three 的渲染循环中运行。 |
用法
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);
// 匹配视口更改
window.addEventListener('resize', () => {
projection.resize([canvas.width, canvas.height]);
});
// 将深度范围拟合到点云
camera.fitNearFar(pointCloud.bbox);
// 上传到 GPU
cameraUniforms.setData({
view: camera.viewMatrix(),
proj: camera.projMatrix(),
position: camera.position(),
});
在 Three.js 中使用 CameraAdapter
const adapter = new CameraAdapter();
adapter.update(threeCamera, [canvas.width, canvas.height]);
preprocessor.dispatchModel({
camera: adapter,
viewport: [canvas.width, canvas.height],
// ... 其他参数
}, encoder);
相关文档