如何让Three.js场景保持camera.position.y视角并在canvas居中?
解决Three.js相机Y轴偏移后场景居中且无倾斜的问题
核心需求拆解
你需要的是:
- 相机
position.y设为任意值时,物体保持正面朝向相机(无倾斜)(和示例2效果一致) - 物体在canvas中垂直、水平完全居中(解决示例2场景偏下的问题)
问题根源
示例2中相机保持默认朝向(沿-z轴),物体正面朝向相机所以无倾斜,但相机在y=7位置时,物体(原点)处于相机视锥体的下方区域,因此在屏幕中偏下。示例1调用lookAt(0,0,0)导致相机倾斜,物体正面不再朝向相机,出现倾斜效果。
实现方案
保持相机默认朝向(沿-z轴,确保物体无倾斜),通过调整投影矩阵偏移视锥体,让物体回到屏幕中央。以下是两种可行方法:
方法1:使用setViewOffset快速偏移
利用Three.js相机的setViewOffset方法,计算视锥体需要向上偏移的像素量,将物体拉回屏幕中央:
// 初始化相机 const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(0, 7, 5); // 保持z轴默认距离,不调用lookAt // 计算并更新相机偏移 function updateCameraOffset() { const canvasWidth = window.innerWidth; const canvasHeight = window.innerHeight; const zDist = camera.position.z; // 相机到物体(原点)的z轴距离 const halfHeight = Math.tan(THREE.MathUtils.degToRad(camera.fov / 2)) * zDist; const yOffsetWorld = camera.position.y; // 相机与物体的y轴偏移量 const offsetRatio = yOffsetWorld / halfHeight; const offsetY = offsetRatio * (canvasHeight / 2); // 向上偏移视锥体,抵消y轴位置差 camera.setViewOffset(canvasWidth, canvasHeight, 0, -offsetY, canvasWidth, canvasHeight); camera.aspect = canvasWidth / canvasHeight; camera.updateProjectionMatrix(); } // 初始化及窗口resize时调用 updateCameraOffset(); window.addEventListener('resize', () => { updateCameraOffset(); renderer.setSize(window.innerWidth, window.innerHeight); });
方法2:手动修改投影矩阵(更精准)
直接构建透视投影矩阵,调整视锥体的上下边界,让物体处于视锥体中心:
// 初始化相机 const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(0, 7, 5); // 更新投影矩阵 function updateCameraProjection() { const n = camera.near; const f = camera.far; const fov = camera.fov; const aspect = camera.aspect; const zDist = camera.position.z; const yOffsetWorld = camera.position.y; const tanFovHalf = Math.tan(THREE.MathUtils.degToRad(fov / 2)); // 调整视锥体上下边界,抵消y轴偏移 const t = n * tanFovHalf - (n * yOffsetWorld) / zDist; const b = -n * tanFovHalf - (n * yOffsetWorld) / zDist; const l = -aspect * n * tanFovHalf; const r = aspect * n * tanFovHalf; camera.projectionMatrix.makePerspective(l, r, b, t, n, f); } // 初始化及窗口resize时调用 updateCameraProjection(); window.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight; updateCameraProjection(); renderer.setSize(window.innerWidth, window.innerHeight); });
适配任意camera.position.y值
无论你将camera.position.y设为多少,只需在修改后调用对应的更新函数(updateCameraOffset或updateCameraProjection),即可自动重新计算偏移,保持场景居中且无倾斜。
内容的提问来源于stack exchange,提问作者Sanjeet M
相关产品推荐
相关产品推荐

