ThreeJS加载GLTF模型时法线与粗糙度纹理不显示求助
ThreeJS加载GLTF法线/粗糙度纹理不显示的解决方案
以下是针对该问题的排查和解决步骤:
1. 补充方向光/点光,解决光照不足问题
当前代码仅使用AmbientLight(环境光),这种无方向的均匀光照无法触发法线纹理的凹凸效果,也难以体现粗糙度纹理的质感。必须添加带有方向的光源:
// 在init函数中scene.add(light);之后添加 const directionalLight = new THREE.DirectionalLight(0xffffff, 1.2); directionalLight.position.set(3, 5, 4); // 可调整位置以获得合适的光影角度 scene.add(directionalLight); // 可选:开启阴影增强真实感 directionalLight.castShadow = true; renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap;
2. 检查并修复材质参数
即使纹理已存在,默认参数可能被重置或未正确配置:
// 在load_gltf的回调函数中,scene.add(gltf.scene);之后添加 gltf.scene.traverse((obj) => { if (obj.isMesh && obj.material.isMeshStandardMaterial) { const mat = obj.material; // 恢复法线强度(默认应为(1,1),若被设为(0,0)则无效果) mat.normalScale.set(1, 1); // 让粗糙度纹理完全生效(将roughness设为1,由纹理控制粗糙度) mat.roughness = 1; // 若模型有金属度纹理,同理设置metalness为1 // mat.metalness = 1; // 强制材质更新 mat.needsUpdate = true; } });
3. 修正纹理编码格式
法线、粗糙度纹理属于数据纹理,需使用线性编码而非sRGB编码,否则会显示异常:
// 同样在load_gltf的回调中添加 gltf.scene.traverse((obj) => { if (obj.isMesh && obj.material) { const mat = obj.material; if (mat.normalMap) mat.normalMap.encoding = THREE.LinearEncoding; if (mat.roughnessMap) mat.roughnessMap.encoding = THREE.LinearEncoding; mat.needsUpdate = true; } });
4. 手动替换材质的正确姿势
若尝试手动替换为MeshStandardMaterial,需完整复制原材质的纹理和参数,避免遗漏:
gltf.scene.traverse((obj) => { if (obj.isMesh) { const oldMat = obj.material; const newMat = new THREE.MeshStandardMaterial({ map: oldMat.map, normalMap: oldMat.normalMap, roughnessMap: oldMat.roughnessMap, normalScale: oldMat.normalScale.clone(), // 克隆向量避免引用问题 roughness: oldMat.roughness, metalness: oldMat.metalness, color: oldMat.color.clone(), transparent: oldMat.transparent, opacity: oldMat.opacity }); // 修正编码 if (newMat.normalMap) newMat.normalMap.encoding = THREE.LinearEncoding; if (newMat.roughnessMap) newMat.roughnessMap.encoding = THREE.LinearEncoding; obj.material = newMat; } });
优先尝试步骤1,因为环境光无法触发法线效果是最常见的原因。若仍未解决,依次检查后续步骤。
内容的提问来源于stack exchange,提问作者Limbo
相关产品推荐
相关产品推荐

