使用Tween.js实现Three.js全景图相机定位到用户点击位置的问题
解决等矩形全景图点击居中问题
你的问题出在直接用屏幕像素差值修改经纬度坐标——屏幕像素和全景图的经纬度不是线性对应关系,这么做自然没法让点击位置准确居中。正确的做法是把点击的屏幕坐标转换成全景图对应的经纬度,再让相机平滑过渡到这个目标经纬度。
核心思路
- 将点击的屏幕坐标归一化到[-1, 1]范围(WebGL标准设备坐标)
- 根据等矩形全景的映射规则,把归一化坐标转换成对应的经度、纬度
- 用Tween.js将当前相机的经纬度平滑过渡到目标值
- 限制经纬度合法范围(纬度不能超过±90°,经度可循环)
修正后的代码
// 处理点击事件 var handlePanoramaClick = function (event) { // 将屏幕坐标归一化到[-1, 1],翻转y轴适配Three.js坐标系 var x = (event.clientX / window.innerWidth) * 2 - 1; var y = -(event.clientY / window.innerHeight) * 2 + 1; // 转换为经纬度(单位:度) var targetLon = x * 180; // x轴对应经度:-1→-180°,1→180° var targetLat = y * 90; // y轴对应纬度:-1→-90°,1→90° // 用Tween.js平滑过渡到目标经纬度 new TWEEN.Tween(coords.latLon.current) .to({ x: targetLat, y: targetLon }, 1000) .start(); }; var update = function update() { var distX = coords.latLon.current.x - coords.latLon.delta.x; var distY = coords.latLon.current.y - coords.latLon.delta.y; coords.latLon.delta.x += distX / 7; coords.latLon.delta.y += distY / 7; // 限制纬度范围,避免相机翻转异常 coords.latLon.delta.x = THREE.Math.clamp(coords.latLon.delta.x, -90, 90); // 经度循环处理,保持在-180°到180°之间 coords.latLon.delta.y = ((coords.latLon.delta.y + 180) % 360) - 180; coords.phi = THREE.Math.degToRad(90 - coords.latLon.delta.x); coords.theta = THREE.Math.degToRad(coords.latLon.delta.y); coords.target.x = 500 * Math.sin(coords.phi) * Math.cos(coords.theta); coords.target.y = 500 * Math.cos(coords.phi); coords.target.z = 500 * Math.sin(coords.phi) * Math.sin(coords.theta); Cam.camera.lookAt(coords.target); renderer.render(Scene, Camera); }; var animate = function animate() { update(); requestAnimationFrame(animate); TWEEN.update(); };
关键说明
- 坐标归一化:把屏幕的[0, 宽度]、[0, 高度]转换成[-1,1]的设备坐标,这是Three.js中全景映射的标准处理方式
- 经纬度映射:等矩形全景的x轴对应左右方向的经度,y轴对应上下方向的纬度,直接按比例映射即可
- 范围限制:纬度必须锁死在±90°,否则相机翻转后会出现画面异常;经度做循环处理,避免超出合理范围
- 平滑逻辑复用:保留了你原来的Tween.js过渡和缓动逻辑,只修改了目标值的计算方式
这样修改后,点击全景图任意位置,相机都会平滑移动到该位置并居中显示。
内容的提问来源于stack exchange,提问作者Vad
相关产品推荐
相关产品推荐

