1

So I have this scene which comes from a glb-file that I imported using GLTFLoader. It contains these objects of guys in different colors. Each object has its material (RedMat, BlueMat, GreenMat etc). The materials are made in Blender and they all use the same texture file (this one) which is basically just a color palette. So the different colors of the objects just comes from each material having different UVs.

enter image description here

This works good so far and the objects have the correct colors when I load them using GLTFLoader and display it in my three.js scene (the screenshot is from a three.js render). But I want to be able to update the material of one object, so that for instance the red object takes the material of the green object.

new GLTFLoader().load('myfile.glb', function (gltf) {
    const redGuy = gltf.scene.children.find(x => x.name === 'RedGuy');
    const greenGuy = gltf.scene.children.find(x => x.name === 'GreenGuy');

    redGuy.material = greenGuy.material; // I expect here that the red guy would become green, but nothing happens
    // But if I instead do this:
    redGuy.material = new THREE.MeshPhongMaterial({color: '#FF0000'});
    // that works, but I want to be able to use the materials I already setup in Blender that are in the glb-file
});

Also if I console.log redGuy.material and greenGuy.material in the console they look pretty much identical, which I find weird, they just have different names and ids.

Obviously this is a short snippet to demonstrate my problem, I hope this is sufficient. Otherwise I could upload the whole project and the Blender-file somewhere if that is needed.

Martin Sonesson
  • 719
  • 1
  • 6
  • 13
  • possible duplicate? https://stackoverflow.com/questions/56660584/how-to-override-gltf-materials-in-three-js – This Guy Jan 09 '23 at 14:30
  • Do you mind sharing the glb file in this thread? – Mugen87 Jan 09 '23 at 14:36
  • 2
    Guessing from the texture atlas, you probably need to transform the UV coordinates of the model, not change the material. The color comes from the positions in the texture. – emackey Jan 09 '23 at 14:40
  • @emackey yes that sounds likely, but I supposed that the UV coordinates was a part of the material. Where do I find the UV coordinates in the child node? It doesn't seem to contain anything regarding that. – Martin Sonesson Jan 09 '23 at 16:27
  • 1
    As you discovered, it's part of the geometry. There's probably some way to apply texture transforms, but looks like just selecting the other geometry works in this case. Also you may be able to optimize a bit, re-use the same Blender material for all these objects since they're all pointing at the same texturemap. – emackey Jan 09 '23 at 20:28
  • @emackey Thank you. Yes in this case this method seems to work, although it doesn't feel optimized because the "geometry" object is actually very big and contains lots of stuff, and I'm not sure what it all is, if I knew which child of geometry had the UV coordinates I could maybe only copy that one. And yes, duplicate materials seems like a waste, it was just my attempt at fixing this problem, by breaking them up into separate materials (even though they are basically the same). – Martin Sonesson Jan 09 '23 at 22:35
  • 1
    Take a look at some texture properties: https://threejs.org/docs/index.html#api/en/textures/Texture.matrixAutoUpdate and https://threejs.org/docs/index.html#api/en/textures/Texture.offset . I think you can offset the UVs without copying any geometry. – emackey Jan 11 '23 at 13:51

1 Answers1

0

Okay so I finally found out the answer. Instead of

redGuy.material = greenGuy.material;

I should write

redGuy.geometry = greenGuy.geometry;

In this case the colors of the different objects are determined by the UV coordinates. I thought these would be a part of the material node, but instead it seems they are in the geometry node.

Martin Sonesson
  • 719
  • 1
  • 6
  • 13