'GLTFLoader does not allow to replace its default materials

I have the following scene.

AmbientLight color: light blue

PointLight color: pink

a loaded gltf object with textures

I loaded a gltf object with texture map using GLTFLoader, the model is correctly loaded with textures using MeshStandardMaterial by default in picture 1. Now I want to change all the MeshStandardMaterial to MeshPhongMaterial, the way I am doing it is just loop through all the meshes, and update the material,for example:

// find gltf scene
var gltfScene = scene.children.find(ele => ele.type === 'Scene');    
var meshes = gltfScene.children;
for (var i = 0; i < meshes.length; i++) {
  // for each mesh, change to MeshPhongMaterial
  meshes[i].material = new THREE.MeshPhongMaterial()
}

however, after I do that, all the mesh color turn to flat color of my AmbientLight color, and they do NOT reacts to light anymore (SpotLight, PointLight) in picture 2, you can see the pink from PointLight is gone.

Could anyone please help on why and how I can replace with MeshPhongMaterial.

here is the codepen https://codepen.io/chen-xu/pen/XWJWbwj, the problem happens if you click on Replace Horse Mesh, you will see the pink light is gone.

default loaded object with MeshStandardMaterial

I change the material to MeshPhongMaterial



Solution 1:[1]

It seems your are not traversing through the glTF scene correctly. It should look like so:

gltf.scene.traverse( ( child ) => { 

    if ( child.isMesh ) {

        child.material = new THREE.MeshPhongMaterial();

    }

} );

three.js R111

Solution 2:[2]

thanks @Mugen87, this answer is also from you on Github, we need to add {flatShading: true}

gltf.scene.traverse( ( child ) => { 

    if ( child.isMesh ) {

        child.material = new THREE.MeshPhongMaterial({flatShading: true});

    }

} );

Solution 3:[3]

I had to do a couple of extra steps to get it to work for me, also with gltf.

gltf.scene.traverse((child) => {

        if (child.isMesh) {

          const originalMaterial = child.material;
          const newMaterial = new THREE.MeshPhongMaterial();

          // these are missing and required
          child.geometry.computeVertexNormals();
          // use the texture from the original material
          newMaterial.map = originalMaterial.map;

          child.material = newMaterial;
      }
})

note: flatShading = true sort of works but won't give you the smoother interpolated shading most people probably want.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Mugen87
Solution 2 user2002692
Solution 3 Tom Greenwood