Changing/Accessing materials of a gltf-Object individually

Hi There.
I exported an object from Blender to a gltf-file and imported it into my three.js project. (Including materials, ive got 2 in total)

let loader = new THREE.GLTFLoader();

loader.load('Objects/MyBox.gltf', (gltf) => {

let box = gltf.scene;

box.traverse((child) => {
                        if (child.isMesh) child.material = boxMaterial; // a material i created in the code earlier
                    });
                    scene.add(box);
                });

This code causes my imported Object (which is a folded box) to have the same material (boxMaterial) on the outside and on the inside.
But as i created it in bleder ( inside of the box has an inside material, the outside has an outside material) i want it to be in my three.js project. What I want is = the boxMaterial(created in three.js) shall only be on the outside-Material(created in blender).

My question is -> how do I tell/access the specific imported material of my imported object to have a certain material in three.js?

in easier words: “child.material” contains my needed materials.(2 in total) But how do I get/access only the first one?

I think I’m looking for something like a box.children[0].material… or something. the index 0 has my outside material.

Thanks in advance!

GLTFLoader does not produce meshes with multiple materials. So child.material is definitely no Array.

TBH, I’m not sure I understand your question. However, you should be able to retrieve all materials of a glTF asset with this code:

gltf.parser.getDependencies( 'material' ).then( ( materials ) => {

	console.log( materials );

} );

You can then traverse through the scene as you already do, compare the material of each child with the above ones and replace it if necessary.

/cc

Thank you for the quick reply.

Blockquote
TBH, I’m not sure I understand your question.

Well, I imported a gltf-file including the materials I need. (When I exported my object from Blender they got included because I gave the Object materials in the first place -> InsideBox, OutsideBox)

When I traversed them (as you can see in my code) I only knew about the option to apply my material (boxMaterial -> which I created in three.js) on to the child.material.

But since “child.material” includes my imported materials “InsideBox” AND “OutsideBox” -> the WHOLE box gets the boxMaterial (In my code: child.material = boxMaterial) even though it should only be on the “OutsideBox”-Material.

So my goal is to access the imported “OutsideBox”-Material, so I can ONLY apply the boxMaterial(which i created in three.js) to the “OutsideBox”-Material but NOT to the “InsideBox”-Material.

Blockquote
However, you should be able to retrieve all materials of a glTF asset with this code:

Thank you, I’ll give it a try!

It is hard for us to know what is in your glTF file without inspecting it. Perhaps try viewing it in https://gltf-viewer.donmccurdy.com/, open the JS Console, and take a screenshot of the output? Something like this, for example:

Screen Shot 2020-03-26 at 9.06.31 AM

If your model had 2 materials and 1 mesh in Blender, I would expect that there are 2 materials and 2 meshes in three.js. We do not import a single mesh with multiple materials.


However, you should be able to retrieve all materials of a glTF asset with this code:

Note that this will give you every material in the original glTF file. That has its uses, but does not necessarily give you every material in the final scene. This is because the loader may need to make copies of some materials, in order to have versions with/without skinning, vertex colors, and so on. If you need to modify the materials that are already applied to your meshes, it’s better to traverse the scene and modify things there.

1 Like

I managed to use only one certain material with the code above -> this solved my problem. so thanks @Mugen87

Maybe I’ll experiece different issues in the future while working on my project. so thank you @donmccurdy for the warning and reply.

For anybody still struggling with this, here’s a code snippet that worked for me. Recurses through all the GLTF’s children, and replaces each material with a new one that has the same texture.

setMaterialsOnGLTF(object3D) {
    if (object3D.material) {
      const newMaterial = new THREE.MeshPhongMaterial( { map: object3D.material.map } );
      object3D.material = newMaterial;
    }
    if (!object3D.children) {
      return;
    }
    for (let i = 0; i < object3D.children.length; i++) {
      Utilities.setMaterialsOnGLTF(object3D.children[i]);
    }
  }

And if you’re using a GLTF, you’ll want to pass in gltf.scene from the loader.