由于浏览器是一个2d视口,而在里面显示three.js的内容是3d场景,所以,现在有一个问题就是如何将2d视口的x和y坐标转换成three.js场景中的3d坐标。好在three.js已经有了解决相关问题的方案,那就是THREE.Raycaster射线,用于鼠标拾取(计算出鼠标移过的三维空间中的对象)。
我们一般都会设置三维场景的显示区域,如果,指明当前显示的2d
坐标给THREE.Raycaster
的话,它将生成一条从显示的起点到终点的一条射线。也就是说,我们再屏幕上点击了一个点,在three.js
里面获取的则是一条直线。
鼠标在屏幕上点击的时候,得到二维坐标p(x, y),再加上深度坐标的范围(0, 1), 就可以形成两个三位坐标A(x1, y1, 0), B(x2, y, 1), 由于它们的Z轴坐标是0和1,则转变到投影坐标系的话,一定分别是前剪切平面上的点和后剪切平面上的点,也就是说,在投影坐标系中,A点一定在能看见的所有模型的最前面,B点一定在能看见的所有的模型的最后边,将AB点连成线,AB线穿过的物体就是被点击的物体。而 Three.js提供一个射线类Raycasting来拾取场景里面的物体。更方便的使用鼠标来操作3D场景。(不过在实际代码中我们组成射线的两个点是摄像机所在视点与屏幕上点击的点连接而成的射线)
思路:先通过当前点击位置的坐标和相机计算出raycaster
线,然后计算出相交的所有模型,修改模型的纹理。
代码实现:
var raycaster = new THREE.Raycaster()
var mouse = new THREE.Vector2()
function onMouseClick(event){
//将鼠标点击位置的屏幕坐标转换成threejs中的标准坐标
mouse.x = (event.clientX / window.innerWidth) * 2 - 1
mouse.y = (event.clientY/window.innerHeight) *2 + 1
// 通过鼠标点的位置和当前相机的矩阵计算出raycaster
raycaster.setFromCamera( mouse, camera );
// 获取raycaster直线和所有模型相交的数组集合
var intersects = raycaster.intersectObjects( scene.children );
console.log(intersects);
//将所有的相交的模型的颜色设置为红色for ( var i = 0; i < intersects.length; i++ ) {
intersects[ i ].object.material.color.set( 0xff0000 );
}
}
window.addEventListener( 'click', onMouseClick, false );