将材质应用于 gltf 对象时出现未定义错误

Undefined Error when applying materials to gltf object

我创建了一个 Three.js 场景,它在 RGBELoader 中加载了一个 GLtf 对象 (.glb)(用于 hdr 环境纹理照明)

然后我给这个 GLtf 对象中的每个网格一个新的 Material。像这样:

              gltfObject.traverse((ChildGLTF) => {

              ChildGLTF.children[0].material = MidMaterial;
              ChildGLTF.children[1].material = TopMaterial;
              ChildGLTF.children[2].material = BotMaterial;
              
            });  

现在奇怪的是,我得到了一个错误,同时 material 应用了我想要的。所以它确实有效。

我仍然想消除该错误或至少了解导致错误的原因。

那是错误:

script.js:77 Uncaught (in promise) TypeError: Cannot set properties of undefined (setting 'material')
at script.js:77
at Mesh.traverse (three.module.js:6907)
at Group.traverse (three.module.js:6913)
at script.js:72
at GLTFLoader.js:175
at GLTFLoader.js:1989

所以我最好的猜测是,有不止一个 .material 属性?但是我如何指定,我只想要可变的 material..

或者 'gltfObject.traverse((ChildGLTF)' 以 ChildGLTF 作为数组运行了不止一次?如果是,“console.log( ChildGLTF[0] );”给出“未定义”..

这是控制台日志

              console.log( ChildGLTF[0] ); //'undefined'
              console.log( ChildGLTF.children[0] ); //works fine
              console.log( ChildGLTF.children[0].material ); //'Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'material')'

console.log( ChildGLTF.children[0] )

! Mesh {uuid: '3BE5076C-A90D-47B4-BE40-D1E77E4F4DEC', name: 'Cube', type: 'Mesh', parent: Group, children: Array(0), …} animations: [] castShadow: false children: [] frustumCulled: true geometry: BufferGeometry {uuid: 'EC8A35A7-1942-4556-9D93-6C3E25F4C77A', name: '', type: 'BufferGeometry', index: BufferAttribute, attributes: {…}, …} layers: Layers {mask: 1} material: MeshStandardMaterial {uuid: 'ACA40D34-B763-42DA-A956-3ABBAC901D37', name: '', type: 'MeshStandardMaterial', fog: true, blending: 1, …} matrix: Matrix4 {elements: Array(16)} matrixAutoUpdate: true matrixWorld: Matrix4 {elements: Array(16)} matrixWorldNeedsUpdate: false name: "Cube" parent: Group {uuid: '27EE9C8E-3B31-4483-8058-CA2DA42070FC', name: 'Scene', type: 'Group', parent: Scene, children: Array(3), …} position: Vector3 {x: 0, y: 0, z: 0} quaternion: Quaternion {_x: 0, _y: 0, _z: 0, _w: 1, _onChangeCallback: ƒ} receiveShadow: false renderOrder: 0 rotation: Euler {_x: 0, _y: 0, _z: 0, _order: 'XYZ', _onChangeCallback: ƒ} scale: Vector3 {x: 1, y: 1, z: 1} type: "Mesh" up: Vector3 {x: 0, y: 1, z: 0} userData: {name: 'Cube'} uuid: "3BE5076C-A90D-47B4-BE40-D1E77E4F4DEC" visible: true drawMode: (...) eulerOrder: (...) id: 40 modelViewMatrix: Matrix4 {elements: Array(16)} normalMatrix: Matrix3 {elements: Array(9)} useQuaternion: (...) [[Prototype]]: Object3D

console.log(ChildGLTF.children[0].material);

! MeshStandardMaterial {uuid: 'FBA72EAB-93C3-4F92-B141-1BA011BB81FD', name: 'CubeMaterial', type: 'MeshStandardMaterial', fog: true, blending: 1, …} alphaMap: null alphaTest: 0 aoMap: null aoMapIntensity: 1 blendDst: 205 blendDstAlpha: null blendEquation: 100 blendEquationAlpha: null blendSrc: 204 blendSrcAlpha: null blending: 1 bumpMap: null bumpScale: 1 clipIntersection: false clipShadows: false clippingPlanes: null color: Color {r: 0.011123105883598328, g: 0.004119289573282003, b: 0.8000000715255737} colorWrite: true defines: {STANDARD: ''} depthFunc: 3 depthTest: true depthWrite: true displacementBias: 0 displacementMap: null displacementScale: 1 dithering: false emissive: Color {r: 0, g: 0, b: 0} emissiveIntensity: 1 emissiveMap: null envMap: null envMapIntensity: 1 flatShading: false fog: true lightMap: null lightMapIntensity: 1 map: null metalness: 0 metalnessMap: null morphNormals: false morphTargets: false name: "CubeMaterial" normalMap: null normalMapType: 0 normalScale: Vector2 {x: 1, y: 1} opacity: 1 polygonOffset: false polygonOffsetFactor: 0 polygonOffsetUnits: 0 precision: null premultipliedAlpha: false refractionRatio: 0.98 roughness: 0.5 roughnessMap: null shadowSide: null side: 2 skinning: false stencilFail: 7680 stencilFunc: 519 stencilFuncMask: 255 stencilRef: 0 stencilWrite: false stencilWriteMask: 255 stencilZFail: 7680 stencilZPass: 7680 toneMapped: true transparent: false type: "MeshStandardMaterial" userData: {} uuid: "FBA72EAB-93C3-4F92-B141-1BA011BB81FD" version: 0 vertexColors: false vertexTangents: false visible: true wireframe: false wireframeLinecap: "round" wireframeLinejoin: "round" wireframeLinewidth: 1 id: 7 overdraw: (...) shading: (...) stencilMask: (...) wrapAround: (...) wrapRGB: (...) [[Prototype]]: Material

.traverse(...) 将 运行 模型中每个 object 的回调,并且您的代码假定每个 object 恰好有三个 children。这是不可能的,因为模型必须无限深,当你最终到达一个没有 children 的 object 时,做 .children[0].material 会抛出这些错误。

您需要检查 ChildGLTF 是什么,并且 在循环期间修改那个 object。

gltfObject.traverse((child) => {
  if (!child.isMesh) return;

  if (child.name === 'MyMidMeshName') { // change this name
    child.material = MidMaterial;
  } else if (child.name === 'MyTopMeshName') { // change this name
    // ...
  } else {
    // ...
  }
});