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

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变量,导致未声明错误。

  • 可行解决方案:

    1. 移除法线贴图(若无需使用):如果模型不需要法线贴图,直接清空材质的法线贴图并更新材质:
      mesh.material.normalMap = null;
      mesh.material.needsUpdate = true;
      
    2. 手动生成切线数据:如果必须保留法线贴图,需为网格强制计算切线,确保着色器能获取到vTBN所需的数据源:
      mesh.geometry.computeTangents();
      mesh.material.flatShading = true;
      mesh.material.needsUpdate = true;
      
    3. 替换为标准材质:若上述方法无效,尝试将原材质替换为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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 17:50:20