ThreeJs入门40-物体旋转的方法和技巧1

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

示例代码采用three.js-r73版本: github.com/mrdoob/thre…

我们现在做了场景渲染物体,通过监听鼠标来改变场景视角,那我们如何通过鼠标来选中物体呢?比如选中物体变色。让我们来看看吧。

我们使用上节渲染的随机几何体来完成鼠标选中功能。

什么是拾取

  • 鼠标选中一个物体就是拾取。

image.png
我们在二维视图中来描述一下三维鼠标点击情况

  • 假设我们右侧相机看向场景中的物体
  • 当我们鼠标点击某个位置之后
  • 鼠标和相机之间的连线穿过的物体(和物体相交),就是我们可以拾取到的
  • 我们可以判断只有第一个相交的物体,然后对其做处理

光线投射Raycaster

  • 这个类用于进行raycasting(光线投射)。 光线投射用于进行鼠标拾取(在三维空间中计算出鼠标移过了什么物体)。
  • Raycaster类是用来实现拾取的一个简单类。说他简单,是因为,你基本不需要去了解他的原理,就可以使用他。
  • 构造函数
THREE.Raycaster = function ( origin, direction, near, far )
复制代码
  • origin:光纤发射出去的地方
  • direction:归一化的方向向量
  • near:光纤发射最近的距离,默认为0
  • far:光纤发射最远的距离,默认为无穷远

注意:如果不传参数,那么这条光线原点和方向都为默认的原点。

setFromCamera方法

setFromCamera: function ( coords, camera )
复制代码
  • 这个方法可以通过相机来设置origin, direction两个属性
  • coords: 鼠标的位置,是一个归一化的设备坐标,必须在-1到1之间
  • camera:光线起源的位置

归一化坐标

  • 归一化坐标优点:我们摄像机使用的是三维世界的世界坐标,通过归一化坐标比较好转化。
  • 假设我们三维世界中归一化坐标在原点,那我们屏幕坐标在左上角,所以需要通过转化函数,把屏幕坐标转化为归一化坐标

image.png

intersectObject方法

intersectObject: function ( object, recursive )
复制代码
  • 这个方法可以计算哪些对象和他相交
  • object —— 检查与射线相交的物体。
  • recursive —— 若为true,则同时也会检查所有的后代。否则将只会检查对象本身。默认值为false。

实战

  • 初始化raycaster
raycaster = new THREE.Raycaster();
复制代码
  • 监听鼠标移动,记录坐标信息
// 鼠标的默认位置是一个二维向量
var mouse = new THREE.Vector2()
document.addEventListener("mousemove", onDocumentMouseMove, false);

function onDocumentMouseMove(event) {
    event.preventDefault();

    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}

复制代码
  • 计算出相机照射到鼠标的光线
 raycaster.setFromCamera(mouse, camera);
复制代码
  • 找到 和射线相交的对象,返回数组(相交的物体不只有一个)
var intersects = raycaster.intersectObjects(scene.children);
复制代码
  • 把当前选中的物体设置为红色,之前选中和未选中的设置为原来的颜色(这里逻辑比较复杂我们用一张图来解释)

image.png

// 如果有相交的物体
if (intersects.length > 0) {
    if (INTERSECTED != intersects[0].object) {
        // 这里选中的物体是上一个选中物体。
        if (INTERSECTED) {
            // 把上一个选中的物体设置为当前色。
            INTERSECTED.material.emissive.setHex(INTERSECTED.currentHex);
        }
        // 设置当前选中的物体
        INTERSECTED = intersects[0].object;
        // 保留当前选中物体,**原本的颜色**
        INTERSECTED.currentHex = INTERSECTED.material.emissive.getHex();
        // 设置当前选中的物体颜色为红色
        INTERSECTED.material.emissive.setHex(0xff0000);
    }
    // 如果没有相交的物体,把选中的物体设置为原来的颜色
} else {
    if (INTERSECTED) {
        INTERSECTED.material.emissive.setHex(INTERSECTED.currentHex);
    }
    // 清空选中物体
    INTERSECTED = null;
}
复制代码

实现效果

  • 鼠标选中物体会变色,离开之后选中的物体变回原来的颜色
  • 下一个选中物体变色

GIF.gif
codepen示例代码

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享