threejs 屏幕空间转世界空间

目前有不少博客里都有介绍转换方法,并且方法都是大同小异的,这里参考的是这篇博客

这里想记录的也不是转换方法,想记录下一个容易犯的误区。正常情况下说到坐标转换都是一个点转换成另一个点,但是从屏幕空间转世界空间我感觉更应该理解为从摄像机的位置向屏幕上的点发出一条射线,此射线非RayCast,只是带方向的线。

	screenToWorld(event) {
    const x = event.clientX;//鼠标单击坐标X
    const y = event.clientY;//鼠标单击坐标Y
    // 屏幕坐标转标准设备坐标
    const x1 = (x / window.innerWidth) * 2 - 1;
    const y1 = -(y / window.innerHeight) * 2 + 1;
    //标准设备坐标(z=0.5这个值并没有一个具体的说法)
    const stdVector = new Vector3(x1, y1, 0.5);

    const worldVector = stdVector.unproject(this.defaultCamera);
  }

一开始用这个转换方法时就想在得到的结果上生成一个球,看是否正确的,结果啥也看不到。
后面猜想是不是距离相机太近(比近平面还近),然后稍微修改了下代码,结果也确实是这样的

screenToWorld(event) {
    const x = event.clientX;//鼠标单击坐标X
    const y = event.clientY;//鼠标单击坐标Y
    // 屏幕坐标转标准设备坐标
    const x1 = (x / window.innerWidth) * 2 - 1;
    const y1 = -(y / window.innerHeight) * 2 + 1;
    //标准设备坐标(z=0.5这个值并没有一个具体的说法)
    const stdVector = new Vector3(x1, y1, 0.5);
    const worldVector = stdVector.unproject(this.defaultCamera);
    
	//获取摄像机世界坐标
    let cameraPos = this.defaultCamera.getWorldPosition(new Vector3());
    //获取射线方向
    let dir = worldVector.clone().sub(cameraPos).normalize();;
    //沿着射线方向延伸100个单位
    let src = cameraPos.clone().add(dir.clone().multiplyScalar(100))
    
    this.createSphere(src);
}

//在指定的位置生成一个球
createSphere(pos){
    var geo = new SphereBufferGeometry(0.5);
    var mat = new MeshStandardMaterial();
    var s = new Mesh(geo,mat);
    this.scene.add(s);
    s.position.copy(pos);
}

请添加图片描述
中间点在模型上没有出现是因为生成在模型后面了。

Three.js中,屏幕坐标(Screen Coordinates)通常指的是用户在显示器上看到的像素坐标,而世界坐标(World Coordinates)则是虚拟3D空间中的位置和方向。要将屏幕坐标换为世界坐标,你需要经过以下几个步骤: 1. **视角(View)矩阵**:这是由摄像机(Camera)的位置、旋和缩放设置的,用于投影从3D空间到屏幕的变换。 2. **投影(Projection)矩阵**:基于相机的透视或正交投影,将3D坐标压缩到2D平面上。 3. **模型视图(ModelView)矩阵**:如果物体有位姿变化(如旋和平移),则乘以该物体的模型矩阵,将局部坐标系换为全局坐标系。 4. **归一化设备坐标(Normalized Device Coordinates, NDC)**:将投影后的坐标除以w分量(因为透视投影会有一个w分量),将其映射到-1到1的范围内。 5. **反向渲染过程**:从NDC坐标开始,通常需要经过以下操作:反向透视除法(inverting the perspective divide)、翻y轴(y轴是倒置的,因为屏幕是从上到下的),然后加上视口偏移(viewport offset)和比例因子(scale factor),得到最终的世界坐标。 这里没有提供具体的代码,但你可以使用`THREE.Vector3`类来进行这些计算。例如,假设你有一个屏幕上的点击坐标`mouse.x` 和 `mouse.y`,你可以这样做: ```javascript // 假设已经设置了camera、projectionMatrix和modelViewMatrix const raycaster = new THREE.Raycaster(); raycaster.setFromCamera({x: mouse.x, y: mouse.y}, camera); const intersects = raycaster.intersectObjects(scene.children); if (intersects.length > 0) { const hitObject = intersects.object; const worldPosition = new THREE.Vector3(); worldPosition.setFromMatrixPosition(hitObject.matrixWorld); console.log(worldPosition); // 输出的就是物体在世界坐标系中的位置 } ```
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值