joken-前端工程师

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: :: :: 管理 ::
  404 随笔 :: 39 文章 :: 8 评论 :: 20万 阅读

在 Three.js 中,可以通过 RaycasterIntersection 来实现对 Mesh 材质或几何体的点击事件捕捉。具体来说,当用户点击画布时,可以发射一条射线(Ray),检测射线与场景中对象的交点,从而判断是否点击到了某个 Mesh


结论

使用 THREE.Raycaster 和鼠标事件监听器,可以轻松实现对 Mesh 的点击事件捕捉,并根据需要获取被点击的材质或几何体信息。


详细展开

1. 核心原理

  • Raycaster:用于发射一条射线,检测射线与场景中对象的交点。
  • Intersection:表示射线与对象的交点信息,包括被点击的对象、交点位置等。
  • 鼠标事件监听:通过监听鼠标点击事件,获取鼠标在画布上的坐标,并将其转换为标准化设备坐标(NDC)。

2. 实现步骤

以下是实现 Mesh 点击事件捕捉的主要步骤:

  1. 监听鼠标点击事件。
  2. 将鼠标坐标转换为标准化设备坐标(NDC)。
  3. 使用 Raycaster 检测射线与场景中对象的交点。
  4. 根据交点信息获取被点击的 Mesh 或其材质。

完整示例

以下是一个完整的代码示例,展示如何实现 Mesh 的点击事件捕捉:

// 创建场景、相机和渲染器
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 创建几何体和材质
const geometry = new THREE.BoxGeometry();
const material1 = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const material2 = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const material3 = new THREE.MeshBasicMaterial({ color: 0x0000ff });

const materials = [material1, material2, material3];
const cube = new THREE.Mesh(geometry, new THREE.MeshFaceMaterial(materials));
scene.add(cube);

// 设置相机位置
camera.position.z = 5;

// 渲染循环
function animate() {
    requestAnimationFrame(animate);
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    renderer.render(scene, camera);
}
animate();

// 鼠标点击事件监听
let mouse = new THREE.Vector2(); // 存储鼠标坐标
let raycaster = new THREE.Raycaster(); // 创建 Raycaster

// 监听鼠标点击事件
window.addEventListener('click', (event) => {
    // 获取鼠标在画布上的坐标
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

    // 更新射线
    raycaster.setFromCamera(mouse, camera);

    // 检测射线与场景中对象的交点
    let intersects = raycaster.intersectObjects(scene.children, true);

    // 如果有交点
    if (intersects.length > 0) {
        const intersectedObject = intersects[0].object; // 被点击的对象
        const faceIndex = intersects[0].face.materialIndex; // 被点击面的材质索引

        console.log('点击了物体:', intersectedObject);
        console.log('点击的面使用的材质索引:', faceIndex);

        // 改变被点击面的颜色
        if (intersectedObject.material instanceof THREE.MeshFaceMaterial) {
            intersectedObject.material.materials[faceIndex].color.set(0xffffff); // 设置为白色
        }
    }
});

代码解析

  1. 创建 Raycaster 和鼠标监听器

    • 使用 THREE.Vector2 存储鼠标坐标。
    • 使用 THREE.Raycaster 发射射线。
  2. 将鼠标坐标转换为 NDC

    • 将鼠标在画布上的像素坐标转换为标准化设备坐标(范围为 [-1, 1])。
  3. 检测交点

    • 使用 raycaster.intersectObjects() 方法检测射线与场景中对象的交点。
    • 返回的 intersects 数组包含所有交点信息。
  4. 获取材质索引

    • 如果几何体使用了 THREE.MeshFaceMaterial,可以通过 intersects[0].face.materialIndex 获取被点击面的材质索引。
  5. 修改材质

    • 根据材质索引,动态修改被点击面的颜色或其他属性。

相关延展

1. 支持多种材质

如果几何体使用了多种材质(如 THREE.MeshFaceMaterial),可以通过 materialIndex 确定被点击面的具体材质。

2. 拾取特定对象

可以通过 raycaster.intersectObjects([specificObject]) 限制射线仅检测特定对象。

3. 移动端支持

在移动端,可以监听 touchstartpointerdown 事件代替鼠标点击事件。

window.addEventListener('touchstart', (event) => {
    const touch = event.touches[0];
    mouse.x = (touch.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(touch.clientY / window.innerHeight) * 2 + 1;
    raycaster.setFromCamera(mouse, camera);
    const intersects = raycaster.intersectObjects(scene.children, true);
    if (intersects.length > 0) {
        console.log('触摸了物体:', intersects[0].object);
    }
});

总结

通过 THREE.Raycaster 和鼠标事件监听器,可以轻松实现对 Mesh 的点击事件捕捉,并根据需要获取被点击的材质或几何体信息。这种方法广泛应用于交互式三维应用中,例如游戏、建筑可视化和虚拟现实。

posted on   joken1310  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示