Forge Viewer中使用THREE.ShaderMaterial导致选择功能异常
Forge Viewer自定义ShaderMaterial选择/高亮问题解决方案
问题现象
- 框选功能(Ctrl+左键拖动)几乎无法选中目标网格
- 鼠标悬停网格时,会错误高亮无关网格
- 选中单个网格时,自定义材质与选择材质出现Z-fighting/拼接异常(需切换到“Leaf Object”或“Last Object”选择模式触发)
问题根源
Forge Viewer的拾取、高亮机制依赖于材质中正确集成Viewer内置的ID渲染管线和深度处理逻辑,直接使用原生THREE.ShaderMaterial会缺失这些关键环节:
- 顶点着色器未处理Viewer的
instanceId和drawId,导致拾取时无法正确识别网格ID - 未正确传递深度信息,引发Z-fighting和拾取判定错误
- 缺少Viewer材质必须的标记属性,导致拾取管线忽略该材质的网格
修复方案
1. 完善Shader代码,集成Viewer拾取逻辑
修改顶点和片段着色器,加入Viewer所需的ID传递和深度处理:
const customMaterial = new THREE.ShaderMaterial({ vertexShader: ` #include <pack_normals> #include <id_vert> // 加入Viewer的ID顶点处理 void main() { #include <id_vert_impl> // 执行ID传递逻辑 gl_Position = projectionMatrix * modelViewMatrix * vec4(position.xyz, 1.0); } `, fragmentShader: ` #include <id_decl_frag> uniform vec3 color; void main() { gl_FragColor = vec4(color, 1.0); #include <id_frag> // 加入Viewer的ID片段处理 #include <final_frag> } `, uniforms: { color: {type: 'v3', value: new THREE.Vector3(0.5, 0, 0)}, // 手动添加Viewer拾取所需的uniform(Viewer会自动填充) objectId: { value: 0 }, drawId: { value: 0 }, instanceId: { value: 0 } }, // 添加Viewer材质标记 isTHREEShaderMaterial: true, needsCustomDepthMaterial: true }); customMaterial.needsUpdate = true;
2. 替换深度材质(解决Z-fighting)
Viewer的选择高亮会使用深度测试,需要为自定义材质指定匹配的深度材质:
// 创建深度材质 const depthMaterial = new THREE.MeshDepthMaterial({ depthPacking: THREE.RGBADepthPacking, side: THREE.DoubleSide }); // 关联到自定义材质 customMaterial.customDepthMaterial = depthMaterial;
3. 确保材质被Viewer拾取管线识别
Viewer会过滤不符合要求的材质,需添加必要的属性:
// 标记为Viewer可处理的材质 customMaterial.__isTransparent = false; // 根据实际情况设置 customMaterial.alphaTest = 0.5; // 如果有透明需求,设置alphaTest避免拾取异常
关键说明
Viewer的StandardSurface和Prism材质虽然基于THREE.ShaderMaterial,但内部已经封装了所有拾取、深度、ID处理的逻辑,直接使用原生ShaderMaterial必须手动补充这些环节才能兼容Viewer的交互系统。
内容的提问来源于stack exchange,提问作者xblz
相关产品推荐
相关产品推荐

