跳到主要内容

三维查看器

查看器要的是 轨道相机 + 一份世界矩阵树 + 一个 GLTF 网格投影,不是自研完整 PBR。场景图(节点 id、local 变换、网格引用)留在 CPU;GPU 是 VBO / IBO / 纹理和 view × proj。只有一个模型要转一转:用引擎。散点/后处理那种自研栈不要扩成渲染器。HUD 用 DOM 或第二张 canvas,同一元素不能再要 2d

1. 场景怎么切

CPU:node 树、轨道球状态、动画时钟
↓ 每帧 world 矩阵
GPU:mesh 资源 × viewProj × 灯光 uniform
拾取:CPU AABB 或 1px ID FBO
HUD:DOM overlay,不进场景 FBO

坐标系:世界单位(GLTF meter 惯例)+ lookAt 视图 + perspective。不要把 2D Camera2D.scale 套到透视上,见 相机

export type OrbitCamera = {
targetX: number;
targetY: number;
targetZ: number;
distance: number;
yaw: number;
pitch: number;
};

export function orbitEye(c: OrbitCamera): { x: number; y: number; z: number } {
const cp = Math.cos(c.pitch);
return {
x: c.targetX + c.distance * cp * Math.sin(c.yaw),
y: c.targetY + c.distance * Math.sin(c.pitch),
z: c.targetZ + c.distance * cp * Math.cos(c.yaw),
};
}

export function zoomOrbit(c: OrbitCamera, factor: number): OrbitCamera {
return {
...c,
distance: Math.min(1e5, Math.max(0.05, c.distance * factor)),
};
}

export function clampPitch(c: OrbitCamera, delta: number): OrbitCamera {
return {
...c,
pitch: Math.min(Math.PI / 2 - 0.04, Math.max(-Math.PI / 2 + 0.04, c.pitch + delta)),
};
}

指针增量用前后两帧 NDC 差,不要 movementX,见 指针到 NDCsetPointerCapture 打在 canvas 上。模型加载失败、无网格、无皮肤,是文档错误,不是「shader 没写对」。

适用:看 GLTF/GLB、简单拆件、剖面。
不适用:为看一个模型写金属度工作流;把查看器当游戏引擎。选型边界见 自研 vs Three

2. 哪层必须 CPU,哪层进 GPU;何时上 Three

归属
节点树、local TRS、显隐、选中 idCPU 文档
蒙皮绑定、动画 clip 时钟CPU(引擎则它内部仍是这份职责)
几何、材质纹理、shadow mapGPU 投影
零件名、属性面板DOM

有 GLTF / PBR / 蒙皮 / 动画剪辑:Three 或 Babylon 当壳,不要在本体系其余章绑它们的 API。引擎不替你做产品文档,也不替你做撤销:mesh.position 不能当唯一数据源。无障碍文本不要画进 mesh。

自研仅当:已有 CPU 场景、只要无光照或简单 Phong、网格自己产。生产默认 WebGL2(Three 默认也是这条)。WebGPU 后端是引擎/探测后的事,adapter null 必须能看模型。

拾取:零件少于几千用 CPU AABB;互交三角再用 ID 缓冲 且只读 1px。热路径禁止全屏读深度。跨源纹理 taint 后不能 readPixels / toBlobpreserveDrawingBuffer 默认 false:截图在本帧提交前读 FBO。

3. 失败形态

症状原因
滚轮乱飞2D scale 当了透视相机
为查看器写了半年着色器该用引擎还在自研 PBR
撤销/协作对不上把引擎 mesh 当文档
拾取 Y 反drawing buffer 左下没翻
白模丢失后不回来上下文恢复没重建 program

权威资料

核对日期:2026-08-26