Three.js行星公转时位置不更新,点击缩放定位错误求助
问题:Three.js太阳系模型点击行星相机定位异常
我用Three.js开发太阳系模型,基础功能正常,但点击公转行星时,相机总是缩放至行星初始位置,点击太阳则正常。
当前实现逻辑:在太阳位置创建不可见父对象,通过animate()中调用parent.rotateY()模拟行星公转,行星自身position未更新,调用矩阵更新函数也无效。
我写了calculateCurrentPosition函数计算行星实时位置,怀疑函数逻辑或位置获取方式有误,用TWEEN实现相机移动动画,求修正函数或提供获取对象实时位置的方法。
相关代码
位置计算函数
function calculateCurrentPosition(initialPos, distance, angularSpeed, time) { console.log(initialPos, distance, angularSpeed, time); if (time === 0) { return initialPos; } var currentAngle = angularSpeed * time; var currentX = initialPos.x + distance * Math.cos(currentAngle); var currentZ = initialPos.z + distance * Math.sin(currentAngle); return { x: currentX, y: initialPos.y, z: currentZ }; }
运动沿X-Z平面进行,因此y值保持恒定
行星创建函数
function createPlanete(size, texture, position, ring) { const geo = new THREE.SphereGeometry(size, 30, 30); const mat = new THREE.MeshStandardMaterial({ map: textureLoader.load(texture) }); const mesh = new THREE.Mesh(geo, mat); const obj = new THREE.Object3D(); obj.add(mesh); if(ring) { const ringGeo = new THREE.RingGeometry( ring.innerRadius, ring.outerRadius, 32); const ringMat = new THREE.MeshBasicMaterial({ map: textureLoader.load(ring.texture), side: THREE.DoubleSide }); const ringMesh = new THREE.Mesh(ringGeo, ringMat); obj.add(ringMesh); ringMesh.position.x = position; ringMesh.rotation.x = -0.5 * Math.PI; } scene.add(obj); mesh.position.x = position; return {mesh, obj} }
解决方案
不需要手动计算位置,直接利用Three.js内置方法获取行星的世界坐标即可:
- 获取行星实时世界坐标
使用Vector3.setFromMatrixPosition方法,从行星的世界矩阵中提取真实位置:
function getPlanetWorldPosition(planetMesh) { const worldPos = new THREE.Vector3(); // 确保矩阵是最新的 planetMesh.updateMatrixWorld(true); worldPos.setFromMatrixPosition(planetMesh.matrixWorld); return worldPos; }
调用该函数得到的坐标,可直接传给TWEEN作为相机移动的目标点。
原计算函数的问题
你的手动计算逻辑错误:行星的初始position是相对于父对象的局部坐标,而非世界坐标。父对象旋转时,行星的世界坐标由父对象的旋转矩阵作用于局部坐标得到,手动用余弦/正弦叠加初始世界坐标的方式和实际变换逻辑不符,必然出错。额外说明
如果在animate函数中先执行了父对象旋转,再调用getPlanetWorldPosition,矩阵通常已经是最新的;若不确定,可手动调用updateMatrixWorld(true)强制更新整个场景的矩阵。
内容的提问来源于stack exchange,提问作者Safi ullah
相关产品推荐
相关产品推荐

