Three.js启用Flat Shading时片段着色器编译失败求助
问题:Three.js r143设置flatShading=true时着色器编译错误
使用Three.js r143版本的GLTFLoader加载模型,正常加载无问题,但设置mesh.material.flatShading = true时,出现“Fragment shader is not compiled”错误,报错显示片段着色器中‘vTBN’未声明。
加载模型代码
function loadModel() { // Load the model gltfLoader.load(modelPath + '.gltf', function (gltf) { for (let i = 0; i < gltf.scene.children.length; i++) { // Skip bones if (gltf.scene.children[i].isBone) { continue; } // If a mesh has multiple segments, then it is a group with an array of children (segments/meshes) // If a mesh only has one segment, then it is a single object (mesh) with no children, not an array of length 1 let numSegments = gltf.scene.children[i].isGroup ? gltf.scene.children[i].children.length : 1; for (let j = 0; j < numSegments; j++) { let mesh = gltf.scene.children[i].isGroup ? gltf.scene.children[i].children[j] : gltf.scene.children[i]; mesh.material.flatShading = true; //mesh.material.needsUpdate = true; } } // Show the model scene.add(gltf.scene); }, undefined, function (error) { console.log(error); } ); }
报错信息
THREE.WebGLProgram: Shader Error 0 - VALIDATE_STATUS false Program Info Log: Fragment shader is not compiled. FRAGMENT ERROR: 0:1233: 'vTBN' : undeclared identifier 1228: normal = normalize( normalMatrix * normal ); 1229: #elif defined( TANGENTSPACE_NORMALMAP ) 1230: vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0; 1231: mapN.xy *= normalScale; 1232: #ifdef USE_TANGENT > 1233: normal = normalize( vTBN * mapN ); 1234: #else 1235: normal = perturbNormal2Arb( - vViewPosition, normal, mapN, faceDirection ); 1236: #endif 1237: #elif defined( USE_BUMPMAP ) 1238: normal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection ); 1239: #endif
解决建议
问题根源:开启
flatShading后,Three.js默认会跳过网格切线(Tangent)的生成逻辑,但你的模型材质启用了法线贴图(TANGENTSPACE_NORMALMAP),着色器仍尝试引用依赖切线数据的vTBN变量,导致未声明错误。可行解决方案:
- 移除法线贴图(若无需使用):如果模型不需要法线贴图,直接清空材质的法线贴图并更新材质:
mesh.material.normalMap = null; mesh.material.needsUpdate = true; - 手动生成切线数据:如果必须保留法线贴图,需为网格强制计算切线,确保着色器能获取到
vTBN所需的数据源:mesh.geometry.computeTangents(); mesh.material.flatShading = true; mesh.material.needsUpdate = true; - 替换为标准材质:若上述方法无效,尝试将原材质替换为Three.js内置的标准材质,确保着色器逻辑兼容:
const newMat = new THREE.MeshStandardMaterial({ color: mesh.material.color, map: mesh.material.map, normalMap: mesh.material.normalMap, flatShading: true }); mesh.material = newMat;
- 移除法线贴图(若无需使用):如果模型不需要法线贴图,直接清空材质的法线贴图并更新材质:
关键注意点:修改材质后必须设置
needsUpdate = true,触发Three.js重新编译着色器,使修改生效。
内容的提问来源于stack exchange,提问作者nanoguy
相关产品推荐
相关产品推荐

