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

如何在Three.js中通过下拉选项修改gITF/glb/fbx等3D模型的墙面纹理

Three.js实现点击网格替换下拉菜单选择的纹理

核心实现分为三个关键环节:射线检测选中目标网格、预加载纹理并监听下拉选择、替换纹理并更新材质

1. 用Raycaster实现网格点击检测

Three.js没有原生点击检测能力,需要通过射线投射判断点击位置与场景中网格的交集:

const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
let selectedMesh = null; // 存储选中的目标网格

// 实时更新鼠标的归一化设备坐标
window.addEventListener('mousemove', (e) => {
  mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(e.clientY / window.innerHeight) * 2 + 1;
});

// 处理点击事件,选中目标网格
window.addEventListener('click', () => {
  raycaster.setFromCamera(mouse, camera);
  // 递归检测场景所有子物体,确保能选中嵌套模型里的网格
  const intersects = raycaster.intersectObjects(scene.children, true);

  if (intersects.length > 0) {
    // 重置之前选中网格的状态(比如高亮)
    if (selectedMesh) {
      selectedMesh.material.emissive.set(0x000000);
    }
    // 选中最靠前的网格
    selectedMesh = intersects[0].object;
    // 可选:给选中网格加高亮反馈
    selectedMesh.material.emissive.set(0x333333);
  } else {
    // 未选中时清空状态
    if (selectedMesh) {
      selectedMesh.material.emissive.set(0x000000);
      selectedMesh = null;
    }
  }
});

2. 处理下拉菜单的纹理选择与预加载

先编写HTML下拉菜单,再预加载纹理并绑定选择事件:

HTML部分

<select id="textureSelector">
  <option value="wood">木纹纹理</option>
  <option value="metal">金属纹理</option>
  <option value="fabric">织物纹理</option>
</select>

JS部分

const textureLoader = new THREE.TextureLoader();
const textureCache = new Map(); // 缓存加载好的纹理,避免重复请求

// 预加载纹理,替换为你的实际纹理路径
textureCache.set('wood', textureLoader.load('/assets/textures/wood.jpg'));
textureCache.set('metal', textureLoader.load('/assets/textures/metal.png'));
textureCache.set('fabric', textureLoader.load('/assets/textures/fabric.webp'));

// 监听下拉菜单选择事件
document.getElementById('textureSelector').addEventListener('change', (e) => {
  const selectedTexture = textureCache.get(e.target.value);
  if (!selectedMesh || !selectedTexture) return;

  // 注意:如果模型材质是共享的,先克隆材质再修改,避免影响其他网格
  if (selectedMesh.material.isMeshStandardMaterial || selectedMesh.material.isMeshBasicMaterial) {
    // 克隆材质(可选,根据你的模型材质是否共享决定)
    // selectedMesh.material = selectedMesh.material.clone();
    selectedMesh.material.map = selectedTexture;
    selectedMesh.material.needsUpdate = true; // 必须设置,触发Three.js材质更新
  }
});

3. 关键注意事项

  • 材质共享问题:从glTF/FBX/glb加载的模型,多个网格可能共用同一材质,直接修改会导致所有用该材质的网格都变纹理。解决办法是在替换前克隆材质:selectedMesh.material = selectedMesh.material.clone();
  • 异步纹理加载:如果纹理加载慢,可以用回调确保加载完成后再替换:
    textureLoader.load('/assets/textures/wood.jpg', (texture) => {
      textureCache.set('wood', texture);
      // 加载完成后可触发替换逻辑
    });
    
  • 目标网格筛选:如果只想让特定网格可被选中,给目标网格加自定义标记:
    // 加载模型后,给目标网格加标记
    targetMesh.userData.isEditable = true;
    
    然后在点击检测时判断:
    const targetIntersect = intersects.find(intersect => intersect.object.userData.isEditable);
    if (targetIntersect) {
      selectedMesh = targetIntersect.object;
      // ...后续逻辑
    }
    
  • 触摸设备适配:监听touchstart事件,获取触摸坐标替换鼠标坐标即可,逻辑和点击一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 15:45:43