How to Modify GLTF Materials in Three.js
Loading GLTF models is a standard practice in Three.js, but changing their appearance dynamically requires accessing and modifying their specific materials. This article provides a straightforward guide on how to traverse a loaded GLTF scene, locate target meshes, and update their material properties such as color, roughness, and textures in real-time.
Loading the GLTF Model
To modify a GLTF model’s materials, you must first load the model
using the GLTFLoader. Once loaded, the model’s 3D object
hierarchy is accessible within the loader’s callback function.
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
const loader = new GLTFLoader();
loader.load('path/to/model.gltf', (gltf) => {
const model = gltf.scene;
scene.add(model);
// Material modification code goes here
});Traversing the Model to Find Materials
GLTF models are often made of nested groups and meshes. To access
specific materials, use the traverse method on the loaded
scene. This method executes a callback function for every descendant
object in the model’s hierarchy.
model.traverse((child) => {
if (child.isMesh) {
console.log('Mesh Name:', child.name);
console.log('Material Name:', child.material.name);
}
});Modifying Specific Materials
Once you have isolated the meshes, you can target specific parts of your model using the mesh name or the material name, which are typically defined in your 3D modeling software (like Blender).
Method 1: Target by Mesh Name
If you know the name of the mesh that holds the material, you can target it directly and update its properties.
model.traverse((child) => {
if (child.isMesh && child.name === 'Car_Body') {
// Change color to red
child.material.color.set(0xff0000);
// Adjust physical properties
child.material.roughness = 0.2;
child.material.metalness = 0.8;
}
});Method 2: Target by Material Name
If a single material is applied to multiple meshes, targeting the material by its name is more efficient.
model.traverse((child) => {
if (child.isMesh && child.material) {
if (child.material.name === 'Chrome_Metal') {
child.material.color.set(0xcccccc);
child.material.metalness = 1.0;
child.material.roughness = 0.1;
}
}
});Method 3: Assigning a New Material
Instead of modifying the existing material, you can replace it entirely with a new Three.js material.
import * as THREE from 'three';
const newMaterial = new THREE.MeshStandardMaterial({
color: 0x00ff00,
roughness: 0.5,
metalness: 0.1
});
model.traverse((child) => {
if (child.isMesh && child.name === 'Glass_Window') {
child.material = newMaterial;
}
});Handling Shared Materials (Cloning)
In many GLTF models, multiple meshes share the exact same material instance. If you modify the material of one mesh, it will automatically update all other meshes sharing that material.
To modify the material of a single mesh without affecting others, clone the material first:
model.traverse((child) => {
if (child.isMesh && child.name === 'Unique_Part') {
// Clone the material to make it unique to this mesh
child.material = child.material.clone();
// Apply changes
child.material.color.set(0x0000ff);
}
});Updating Textures
To replace or add a texture to a GLTF material, use the
TextureLoader to load your image, then assign it to the
material’s map property.
const textureLoader = new THREE.TextureLoader();
const newTexture = textureLoader.load('path/to/texture.jpg');
// Ensure correct texture orientation for GLTF models
newTexture.flipY = false;
model.traverse((child) => {
if (child.isMesh && child.name === 'Tshirt') {
child.material.map = newTexture;
child.material.needsUpdate = true; // Tell Three.js to render the new texture
}
});