目前有不少博客里都有介绍转换方法,并且方法都是大同小异的,这里参考的是这篇博客
这里想记录的也不是转换方法,想记录下一个容易犯的误区。正常情况下说到坐标转换都是一个点转换成另一个点,但是从屏幕空间转世界空间我感觉更应该理解为从摄像机的位置向屏幕上的点发出一条射线,此射线非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);
}
中间点在模型上没有出现是因为生成在模型后面了。