选择三维模型对象(射线拾取)

   在canvas画布上使用鼠标单击选中一个三维模型对象,三维模型然后做出反应,比如弹出一个窗口、颜色发生变化。 要实现这一点首先把鼠标单机位置的屏幕坐标转化为标准设备坐标,然后要借助Vector3对象的方法unproject把标准设备坐标转化为世界坐标。 然后利用鼠标单击位置对应的屏幕坐标转化得到的世界坐标和相机对象的世界坐标两个参数创建一个射线对象Raycaster

   下面的代码完成的作用是当鼠标单击canvas画布的时候,如果选中一个网格模型的时候,该网格模型的材质对象由不透明状态变为半透明状态。

    /**
     * 射线拾取函数
     * 选中的网格模型变为半透明效果
     */
    function ray() {
        var Sx = event.clientX;//鼠标单击位置横坐标
        var Sy = event.clientY;//鼠标单击位置纵坐标
        //屏幕坐标转标准设备坐标
        var x = ( Sx / window.innerWidth ) * 2 - 1;//标准设备横坐标
        var y = -( Sy / window.innerHeight ) * 2 + 1;//标准设备纵坐标
        var standardVector  = new THREE.Vector3(x, y, 0.5);//标准设备坐标
        //标准设备坐标转世界坐标
        var worldVector = standardVector.unproject(camera);
        //射线投射方向单位向量(worldVector坐标减相机位置坐标)
        var ray = worldVector.sub(camera.position).normalize();
        //创建射线投射器对象
        var raycaster = new THREE.Raycaster(camera.position, ray);
        //返回射线选中的对象
        var intersects = raycaster.intersectObjects([boxMesh,sphereMesh,cylinderMesh]);
        if (intersects.length > 0) {
            intersects[0].object.material.transparent = true;
            intersects[0].object.material.opacity = 0.6;
        }
    }
    addEventListener('click',ray);// 监听窗口鼠标单击事件

鼠标事件

   通过方法addEventListener可以实时监控鼠标事件,一旦发生鼠标单击事件就执行函数ray()。 执行ray函数,首先通过鼠标事件的返回的事件对象event的坐标属性clientX、clientY获得鼠标单机位置相对浏览器窗口客户区的坐标(单位:像素)。 参考教程HTML5事件

标准设备坐标

        //屏幕坐标转标准设备坐标
        var x = ( Sx / window.innerWidth ) * 2 - 1;//标准设备横坐标
        var y = -( Sy / window.innerHeight ) * 2 + 1;//标准设备纵坐标
        var standardVector  = new THREE.Vector3(x, y, 0.5);//标准设备坐标

   通过返回的坐标值clientX、clientY读入坐标变换公式转化为标准设备坐标系下标准设备坐标x、y,z可以随意自定义一个值。 参考教程世界坐标转化为屏幕坐标

世界坐标

    //标准设备坐标转世界坐标
    var worldVector = standardVector.unproject(camera);

   unproject是Vector3对象的方法,作用是把标准设备坐标转化为世界坐标,方法的参数是相机对象camera,该方法的使用可以参考Vector3对象的project方法, 这两个方法的作用都是进行坐标变换,只不过方向是反过来的。

标准设备坐标
[Not supported by viewer]
世界坐标
[Not supported by viewer]
方法unproject
[Not supported by viewer]
方法project
[Not supported by viewer]

射线发射器对象Raycaster

格式:RaycasterRaycaster( origin, direction, near, far ),origin表示射线起点位置,direction表示射线方向,两个参数的数据类型都是Vector3对象。

   通过构造函数new THREE.Raycaster(camera.position, ray);创建一个射线发射器对象,camera.position是相机的位置,ray表示射线方向向量, 通过语句ray = worldVector.sub(camera.position).normalize();创建,sub是Vector对象的一个方法,两个坐标值(向量)进行减法运算, normalize()方法表示对象向量进行归一化计算,计算相机对象与上面转换得到的世界坐标进行减法运算,然后归一化得到一个单位向量。

   通过射线发射器对象的方法intersectObjects可以返回射线旋转的所有对象,该方法的参数是一个Object3D对象构成的数组,表示射线对象的选择范围,凡是选中的都会以数组的形式返回, 返回的数据结构是[ { distance, point, face, faceIndex, indices, object },{ distance, point, face, faceIndex, indices, object } ... ], 比如案例代码中参数[boxMesh,sphereMesh,cylinderMesh],如果两个网格模型屏幕坐标位置是重合的,那么都会被选中,因此可以通过数组下标的形式访问第几个对象, 被选中的网格模型对象以object属性的形式存在,代码intersects[0].object就表示被选中所有的网格模型中的第一个网格模型对象。 通过语句intersects[0].object.material.opacity = 0.6;可以更改材质对象的透明度。