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

Three.js多材质对象无法结合RayCasting实现点击材质追踪

解决Three.js中RayCasting无法获取多材质Mesh点击材质的问题

我之前也踩过这个坑!单个多材质的Mesh用Raycast确实只能命中对象本身,没法直接拿到点击的具体材质,给你两个实用的解决思路:

方法一:拆分多材质Mesh为单个材质的子网格

不管是在Blender里预处理,还是加载后在Three.js中拆分,把原Mesh拆成每个材质对应一个子Mesh,这样Raycast就能直接命中对应子网格,进而获取材质:

在Three.js中动态拆分的代码示例:

// 假设加载完成后的多材质网格是loadedMesh
const meshParent = new THREE.Object3D();
const originalGeometry = loadedMesh.geometry;
const originalMaterials = loadedMesh.material;

// 遍历每个材质组,创建对应子网格
originalGeometry.groups.forEach((group, idx) => {
  const subGeometry = originalGeometry.clone();
  subGeometry.clearGroups();
  subGeometry.addGroup(group.start, group.count, 0);
  
  const subMesh = new THREE.Mesh(subGeometry, originalMaterials[idx]);
  subMesh.position.copy(loadedMesh.position);
  subMesh.rotation.copy(loadedMesh.rotation);
  subMesh.scale.copy(loadedMesh.scale);
  
  meshParent.add(subMesh);
});

// 替换场景中的原网格
scene.remove(loadedMesh);
scene.add(meshParent);

这样处理后,点击时Raycast返回的intersects[0].object就是对应材质的子Mesh,直接取.material就能拿到目标材质了。

方法二:通过FaceIndex匹配材质组

如果不想拆分网格,可以利用Raycast返回的faceIndex,结合几何体的groups属性判断该面属于哪个材质组,进而获取对应材质:

点击事件中的处理代码:

function handleMouseClick(event) {
  // 初始化Raycaster(常规步骤,这里省略相机和鼠标坐标转换)
  const raycaster = new THREE.Raycaster();
  const mouse = new THREE.Vector2();
  // ... 鼠标坐标转换代码 ...
  
  raycaster.setFromCamera(mouse, camera);
  const intersects = raycaster.intersectObjects(scene.children);
  
  if (intersects.length > 0) {
    const hit = intersects[0];
    const { faceIndex, object } = hit;
    const { geometry, material } = object;
    
    // 遍历材质组,找到包含当前faceIndex的组
    let targetMaterialIdx = -1;
    for (const group of geometry.groups) {
      if (faceIndex >= group.start && faceIndex < group.start + group.count) {
        targetMaterialIdx = group.materialIndex;
        break;
      }
    }
    
    if (targetMaterialIdx !== -1) {
      const clickedMaterial = material[targetMaterialIdx];
      console.log("你点击到的材质:", clickedMaterial);
      // 这里可以写你的业务逻辑
    }
  }
}

注意:要确保Blender导出OBJ时保留了材质分组信息,不然Three.js加载后的geometry.groups会是空数组,这个方法就失效了。

内容的提问来源于stack exchange,提问作者user1771029

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:58:23