HTML5本身不提供“建模相机”,Three.js等库中的第一人称/第三人称视角切换需修改camera.position与lookAt,并重置controls、quaternion及坐标原点,避免状态冲突导致漂移或卡死。
所谓“建模相机”是 Three.js、Babylon.js 等 3D 库对 Camera 对象的封装,HTML5 本身只提供 Canvas 渲染上下文,不内置 3D 场景、视角或坐标系。你实际要控制的是这些库中的相机实例(如 THREE.PerspectiveCamera),而非浏览器 API。
position 和 lookAt
第一人称视角(FPS):相机位置在角色“眼睛”处,朝向由鼠标/键盘实时计算;第三人称视角(TPS):相机位于角色后上方,随角色移动而跟随,通常带平滑插值和距离约束。
camera.position.set(0, 1.6, 0); // 假设角色身高 1.6m
camera.lookAt(new THREE.Vector3(0, 1.6, -1)); // 初始前向
const offset = new THREE.Vector3(0, 1.2, 3); // 相机相对角色的偏移
function updateTPSCamera() {
camera.position.copy(character.position).add(offset);
camera.lookAt(character.position);
}
controls:若用了 PointerLockControls(FPS),切 TPS 前要调用 controls.dispose();TPS 常配 OrbitControls,但需禁用旋转(enableRotate = false)并手动更新目标不是代码没写,而是状态没清或坐标没对齐:
camera.rotation 和 camera.quaternion 冲突:FPS 模式下常直接操作 quaternion,TPS 切换前未重置为单位四元数 —— 必须执行 camera.quaternion.set(0, 0, 0, 1)
group 或 mesh 坐标原点不在脚底:导致 character.position 实际是臀部或重心,TPS 的 lookAt 会朝向错误高度 —— 建议统一用角色的 boundingBox.min.y 校准“地面高度”update() 和 FPS 的 controls.update() 同时运行,造成 position 被反复覆盖 —— 切换时应设标志位(如 isFirstPerson = false),在渲染循环中分支处理PointerLockControls 在 iOS 和多数安卓浏览器中不可用,强行调用会静默失败。替代方案是:
touchstart/touchmove 手动累积 yaw/pitch 角度,再更新 camera.quaternion
DragControls 或自定义拖拽逻辑,禁用双指缩放(event.preventDefault() 阻止 pinch-zoom)ontouchstart="this.style.opacity='0.7'" 提供触控反馈,否则用户不知道已触发camera 实例。漏掉任何一项状态同步(尤其是四元数、父级变换、controls 实例生命周期),都会导致视角漂移或锁死。