You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测Three.js中立方体被点击的面?

立方体面点击检测方案:射线检测及替代方法

当然可以用射线检测(Raycasting)来实现立方体面的点击检测,这也是Three.js中处理这类交互最常用的方法之一。结合你提供的带morphTargets的立方体代码,我给你详细讲讲实现方式,以及其他可行的替代方案:

一、射线检测(Raycasting)实现步骤

这是最直接的方案,Three.js内置的Raycaster可以完美处理这类点击交互,哪怕你的立方体用了morphTargets也不受影响——因为射线检测是基于当前渲染的几何体状态计算的。

具体实现代码

你只需要在现有代码基础上添加以下交互逻辑:

// 初始化射线检测器和鼠标坐标向量
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();

// 监听鼠标点击事件
window.addEventListener('click', (event) => {
    // 把屏幕坐标转换成Three.js的标准化设备坐标(范围:-1 到 1)
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

    // 设置射线的起点(相机位置)和方向(从相机指向点击点)
    raycaster.setFromCamera(mouse, camera);

    // 检测射线与立方体的相交情况
    const intersects = raycaster.intersectObject(mesh);

    if (intersects.length > 0) {
        const clickedFace = intersects[0].face;
        // 将面的法线转换到世界坐标系(因为立方体可能有旋转/位移)
        const worldNormal = clickedFace.normal.clone();
        worldNormal.transformDirection(mesh.matrixWorld);

        // 通过法线方向判断是哪个大面
        if (Math.abs(worldNormal.x) > 0.9) {
            console.log(worldNormal.x > 0 ? "点击了X正方向的面" : "点击了X负方向的面");
        } else if (Math.abs(worldNormal.y) > 0.9) {
            console.log(worldNormal.y > 0 ? "点击了Y正方向的面" : "点击了Y负方向的面");
        } else if (Math.abs(worldNormal.z) > 0.9) {
            console.log(worldNormal.z > 0 ? "点击了Z正方向的面" : "点击了Z负方向的面");
        }
    }
});

注意事项

  • 确保你的相机对象camera已经正确初始化并添加到场景中
  • 如果场景中有多个物体,想要检测子物体的话,可以给intersectObject传第二个参数true(比如raycaster.intersectObject(scene, true))

二、替代方案:拆分立方体为独立面Mesh

如果觉得处理法线太麻烦,可以把立方体拆成6个独立的平面Mesh,每个平面对应一个面,这样点击时直接判断相交的是哪个Mesh即可,逻辑更直观。

示例思路

// 创建正面
const frontGeometry = new THREE.PlaneGeometry(200, 200);
const frontMaterial = new THREE.MeshLambertMaterial({ color: 0xffff00 });
const frontMesh = new THREE.Mesh(frontGeometry, frontMaterial);
frontMesh.position.z = 100; // 放到立方体正面位置
frontMesh.name = "front-face"; // 给面命名,方便识别
scene.add(frontMesh);

// 同理创建其他5个面...

// 点击检测逻辑
window.addEventListener('click', (event) => {
    // 同样转换鼠标坐标、设置射线
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
    raycaster.setFromCamera(mouse, camera);

    const intersects = raycaster.intersectObjects(scene.children);
    if (intersects.length > 0) {
        const clickedMesh = intersects[0].object;
        if (clickedMesh.name.includes("face")) {
            console.log(`点击了${clickedMesh.name}`);
        }
    }
});

三、小众方案:包围盒面检测(不推荐)

你还可以通过THREE.Box3获取立方体的包围盒,然后手动计算点击点与包围盒六个面的碰撞关系,但这种方法实现起来繁琐,且不如射线检测灵活,一般只在特定场景下使用,这里就不展开细讲了。

内容的提问来源于stack exchange,提问作者Tristan F.-R.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 03:55:58