Three.js 相交Mesh着色时所有网格均被错误重着色问题咨询
问题根因
- 最高概率原因:场景中所有Mesh共用了同一个
THREE.Material实例。three.js中材质为引用传递,修改单个实例的属性会同步生效到所有引用该材质的Mesh上。 - 次要原因:现有渲染逻辑没有对未命中射线检测的Mesh做颜色重置,所有曾经被射线命中过的Mesh都会保持红色,运行一段时间后也会出现全量Mesh变红的现象。
解决方案
第一步:修正材质实例复用问题
初始化每个Mesh时单独创建材质实例,不要全局复用同一个材质对象:
// 错误写法:所有Mesh共用同一个材质 const commonMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff }); const mesh1 = new THREE.Mesh(geometry, commonMaterial); const mesh2 = new THREE.Mesh(geometry, commonMaterial); // 正确写法1:每个Mesh单独创建材质 const mesh1 = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ color: 0xffffff })); const mesh2 = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ color: 0xffffff })); // 正确写法2:需要复用材质属性时调用clone()生成新实例 const mesh2 = new THREE.Mesh(geometry, commonMaterial.clone());
第二步:修正渲染逻辑,增加颜色重置流程
每次渲染前先将所有Mesh的颜色恢复为默认值,再给命中的Mesh设置红色:
// 替换为你场景中Mesh的默认颜色 const DEFAULT_COLOR = '#ffffff'; function render() { // 遍历重置所有Mesh颜色 scene.traverse((obj) => { if (obj.isMesh) { (obj as THREE.Mesh).material.color.set(DEFAULT_COLOR); } }); raycaster.setFromCamera(mouse, camera); // 若Mesh放在Group等容器下,将第二个参数改为true开启递归检测 const intersects = raycaster.intersectObjects(scene.children, true); if (intersects.length > 0) { const targetMesh = intersects[0].object as THREE.Mesh; targetMesh.material.color.set('#f00'); } renderer.render(scene, camera); }
额外排查点
修改后如果问题仍存在,可打印不同Mesh的材质ID确认是否仍存在引用复用:
// 两个Mesh打印出的id相同则代表共用了同一个材质实例 console.log(mesh1.material.id, mesh2.material.id);
内容的提问来源于stack exchange,提问作者Frederik
相关产品推荐
相关产品推荐

