You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ThreeJS中将屏幕空间XY坐标转换为指定Z位置透视投影坐标的方法

透视相机下固定屏幕锚点+指定深度物体实现方案

你的思路方向是对的,核心就是通过矩阵逆运算将屏幕坐标映射到指定深度的3D世界坐标,不需要使用正交相机,物体全程处于透视投影空间,可随时脱离锚定状态参与物理交互,具体实现如下:

核心原理

透视投影的本质是把3D世界坐标通过视图矩阵(相机空间转换)、投影矩阵(裁剪空间转换)映射到[-1,1]范围的归一化设备坐标(NDC),反过来把指定屏幕位置的NDC坐标配合目标深度,通过两个矩阵的逆运算就能还原回世界坐标。ThreeJS已经封装好了现成的运算方法,不需要手动推导矩阵。

  • 坐标归一化转换
    屏幕坐标原点默认在左上角,先转成WebGL标准NDC坐标(x、y范围均为[-1,1],x=-1对应屏幕最左、x=1对应最右,y=-1对应屏幕最下、y=1对应最上):
    // 以左下角锚点为例,screenX=0、screenY=窗口高度
    const ndcX = (screenX / window.innerWidth) * 2 - 1
    const ndcY = -(screenY / window.innerHeight) * 2 + 1
    
  • 目标位置计算
    你需要物体距离相机5个单位长度,直接通过反投影拿到屏幕点对应的世界空间射线,沿射线取对应长度的点即可,不需要手动计算逆矩阵:
    // 全局复用向量,避免每帧创建对象产生性能开销
    const rayPoint = new THREE.Vector3()
    const targetPos = new THREE.Vector3()
    
    /**
     * 更新锚定物体位置
     * @param {THREE.PerspectiveCamera} camera 场景透视相机
     * @param {THREE.Object3D} anchorObj 需要锚定的3D物体
     * @param {number} screenX 锚点屏幕x坐标
     * @param {number} screenY 锚点屏幕y坐标
     * @param {number} distanceToCamera 物体到相机的欧氏距离
     */
    function updateAnchor(camera, anchorObj, screenX, screenY, distanceToCamera) {
      // 填充NDC坐标,z值填0.5仅用于获取射线方向
      rayPoint.set(
        (screenX / window.innerWidth) * 2 - 1,
        -(screenY / window.innerHeight) * 2 + 1,
        0.5
      )
      // 反投影得到射线上的世界空间点
      rayPoint.unproject(camera)
      // 计算相机到该点的单位方向向量
      const dir = rayPoint.sub(camera.position).normalize()
      // 沿方向移动指定距离得到目标位置
      targetPos.copy(camera.position).addScaledVector(dir, distanceToCamera)
      // 更新物体位置
      anchorObj.position.copy(targetPos)
    }
    
  • 调用时机
    把updateAnchor方法放到渲染循环中,在相机移动、旋转、视口尺寸变化、相机fov调整后执行即可。锚定状态下物体的屏幕相对位置、透视视觉尺寸会完全保持固定,和你预期的效果一致。

注意:该方案下锚定物体是普通的透视空间3D对象,没有任何特殊层级或渲染约束,需要取消锚定时直接停止调用updateAnchor即可,物体会停在当前位置,可直接接入物理系统和其他场景对象交互,无需额外转换。

内容的提问来源于stack exchange,提问作者Kyle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 18:42:37