three.js实现屏幕坐标转化为模型的世界坐标
基础:three.js中坐标系统.doc
方法.project
通过Vector3对象的方法project,方法的参数是相机对象,语句worldVector.project(camera);返回的结果是世界坐标worldVector在camera相机对象矩阵变化下对应的标准设备坐标, 标准设备坐标xyz的范围是[-1,1]。
因为canvas画布是全屏状态,完全填充浏览器窗口的客户区,canvas画布的宽高尺寸就是window.innerWidth、window.innerHeight。 画布的中心从屏幕坐标系的角度看是坐标是(window.innerWidth/2,window.innerHeight/2),从WebGL标准设备坐标系的角度看是坐标原点(0,0).
主要参考博客:
平面坐标转场景坐标
这种转换由于是由2D转换为3D,所以转换过于以后,平面的坐标在场景坐标内的位置应该是从相机的near到far的一条直线。所以我们无法确定单个点的坐标,一般都是使用当前2D平面的坐标生成一条射线raycaster,来检测当前射线是否和模型产生相交,而获取到当前模型上的位置以及相关信息。
Three.js也给我们封装了转换的方法,我们只要会使用,就能够实现当前的效果,原理是:
首先,获取到当前平面坐标,平面的中心点是(0, 0),左上角的坐标是(-1, 1),右下角的坐标是(1, -1)。我们可以通过当前鼠标距离浏览器窗口减去显示区域距离窗口左上角计算出鼠标距离显示区域左上角的偏移量:
let left = wrap.getBoundingClientRect().left;
let top = wrap.getBoundingClientRect().top;
let clientX = event.clientX - left;
let clientY = event.clientY - top;
然后根据获取到的偏移量计算出平面坐标:
let mouse = new THREE.Vector2();
mouse.x = (clientX / wrap.offsetWidth) * 2 - 1;
mouse.y = -(clientY / wrap.offsetHeight) * 2 + 1;
使用射线通过二维坐标和相机更新射线位置:
let raycaster = new THREE.Raycaster();
raycaster.setFromCamera(mouse, camera);
1
2
最后遍历所有场景内的模型判断是否和当前射线相交:
let intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length >= 1){
alert("有相交的模型");
}
intersectObjects方法如果传第二个值为true,将遍历数组内的所有模型的子类,也就是深度遍历。如果当前没有模型相交,将返回一个空数组,如果有模型,数组内的模型将按照相交距离从近到远排序,每一个对象里面将有以下几个属性:
point:和模型相交的点的坐标位置
face:相交的模型的当前的三角形面片
object:相交的模型对象
distance:相交的点距离相机的位置
由于这个之前也有案例,在这里就发一下之前的案例吧:点击这里
场景世界坐标转平面二维坐标
场景世界坐标转平面二维坐标相对来说就简单了一些,首先,我们需要得到当前点在世界中的坐标位置,如果是某个场景组Group里面的模型的位置坐标那种,我们可以通过模型的方法localToWorld方法获取到世界坐标:
let position = mesh.localToWorld();
1
然后通过THREE.Vector3的project方法,逆转相机来求出二维坐标:
let vec2 = position.project(camera);
1
返回的是一个二维向量,我们可以通过获取的坐标计算出当前点距离显示平面左上角的像素距离。
let halfWidth = window.innerWidth / 2;
let halfHeight = window.innerHeight / 2;
案例默认是显示平面大小为显示窗口的大小,所以直接使用窗口计算:
$(".one").css({
left:vec2.x * halfWidth + halfWidth,
top:-vec2.y * halfHeight + halfHeight
});
我们需要在每帧里面调用,然后持续获取当前的位置。
案例查看地址:点击这里