GLB Replace mesh material on traverse with MeshPhysicalMaterial results in black

Hi,

I’m traversing through a loaded GLB and when I find the mesh.name === “floor” I want to replace that texture with a MeshPhysicalMaterial so I get a env reflection from it.

However, this just ends up black. If I do this on a shere on plane etc, it works fine, if I use MeshBasicMaterial it switches the textre and is visible but no env reflection as its not MeshPhysicalMaterial.

Yes there are lights in the scene.

Test code that works (but I need it on a specific mesh by name in the GLB/GLTF):

const tex2 = this.textureLoader.getTextureByName("floorDiffuse");
const tex3 = this.textureLoader.getTextureByName("floorNormal");

const geometry = new THREE.SphereGeometry(4, 64, 32);
let mat = new THREE.MeshPhysicalMaterial({
	roughness: 0,
	clearcoat: 0.1,
	clearcoatRoughness: 0.1,
	map: tex2,
	normalMap: tex3,
});

let mesh2 = new THREE.Mesh(geometry, mat);
this.scene.add(mesh2);

Code that doesn’t work:

this.room.traverse(mesh => {

	if (mesh.isMesh) {
		if (mesh.name.toLowerCase().includes("floor")) {
		
		// Doesn't work (floor displays as black)
		let mat1 = new THREE.MeshPhysicalMaterial({
			roughness: 0,
			clearcoat: 0.1,
			clearcoatRoughness: 0.1,
			map: tex2,
			normalMap: tex3,
		});
		
		// Works
		let mat2 = new THREE.MeshBasicMaterial({ map: tex2 });
		
		mesh.material = mat1;
		mesh.material.needsUpdate = true;

		}
	}
	
});

I’ve also noticed, sometimes if I drag the browser around the floor flickers into the wood texture but then eventually goes back to full black.

NOTE: I can do this in Blender, but I need control in code for dynamic configurations.

Anyone got any ideas?

Could that be a Z-fighting issue?

No, it’s basically a single plane (floor of a room), but if I set the room floor texture settings accordingly in blender before export it works but I need control in code.

i had something like this recently with normalmaps causing the surface to be black or warped if the texture encoding was not set to LinearEncoding. it’s probably not the issue here but maybe it is … try meshphysicalmaterial without the normalmap as well. also check if metalness is too high.

The texture coordinate conventions of glTF requires to set Texture.flipY to false for your textures. Besides, color textures like floorDiffuse require Texture.encoding to be THREE.sRGBEncoding. All noted in the docs: three.js docs

Oddly, just re-opened project and npm run server and it’s working… No idea… However…

LinearEncoding lightened it up my TextureLoader which takes a config file for setup was setting them to sRGBEncoding, which resulted in a darker texture. Looks much better.

flipY didn’t seem to do anything, sRGBEncoding was already set as a default from my TextureLoader but LinearEncoding resulted in a better result.


However the normal map pretty much nuked the envMap reflectivity…

What is the best way to apply a custom envMap to an existing texture in a glb via mesh traverse? I can’t use scene.environment as this is global.

weird, but if it works it works. just to make sure: if gl.outputEncoding equals srgbencoding then map also has to be srgb. normalmap on the other hand and other data textures should be linear.