GLB File loaded in a react three fiber project looks greyscale

Hey Guys,

I’m loading a GLB file in my react project. The file loads up, however there are no colors.
If I load the same file in vanilla js, it loads up with all the colors.

Note: The glb file looks proper in Blender and sandbox.babylonjs.com. However if I open the same GLB in gltf-viewer.donmccurdy.com it doesn’t show any colors.

Below is the code for my react component. I’m not sure if it’s an issue with the code or the GLB file.

Here is the link to the GLB file: city.glb - Google Drive

import React from "react";
import { Canvas } from "@react-three/fiber";
import { OrbitControls, useGLTF } from "@react-three/drei";
import * as THREE from "three";

// This component handles the loading and displaying of your GLB model
function WorldModel({ path }) {
	const { nodes, materials, scene } = useGLTF(path);
	return <primitive object={scene} />;

	// tried nodes.Scene but the scene still looks greyscale
	// return <primitive object={nodes.Scene} />;

	// tried passing materials to the primitive but the scene still looks greyscale
	// return <primitive object={scene} material={materials} />;
}

function World() {
	return (
		<div style={{ height: "100vh" }}>
			<Canvas gl={{ antialias: true, toneMapping: THREE.NoToneMapping }} linear>
				<ambientLight intensity={1} />
				<directionalLight position={[0, 10, 5]} intensity={1} />

				<WorldModel path="/models/city.glb" />

				<OrbitControls />
			</Canvas>
		</div>
	);
}

export default World;

useGLTF.preload("/models/city.glb");

Below is the vanilla js code

import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";

const loader = new GLTFLoader();

const container = document.createElement("div");
document.body.appendChild(container);

const scene = new THREE.Scene();

const renderer = new THREE.WebGLRenderer();

container.appendChild(renderer.domElement);

const camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 100);
camera.position.set(34, 16, -20);
scene.add(camera);

loader.load("models/gltf/city.glb", function (gltf) {
	scene.add(gltf.scene);
});

function rendeLoop() {
	renderer.render(scene, camera); // render the scene using the camera
	requestAnimationFrame(rendeLoop); //loop the render function
}

rendeLoop(); //start rendering

@adeshchopade maybe try the attached version of that model.

The original model did show properly in my GLTFS Viewer, which is using older version of three.js (r150), so I just re-exported it to GLB from there. It is DRACO compressed so keep that in mind or just use the viewer yourself and export to whatever GLB version you prefer.

city_GLB_DRACO.zip (4.2 MB)

1 Like

This model uses an older glTF extension for spec/gloss PBR, “KHR_materials_pbrSpecularGlossiness”, which has since been archived by Khronos. three.js dropped support for that extension — it required custom ShaderMaterial output from three.js and wasn’t compatible with MeshStandardMaterial or MeshPhysicalMaterial, which use the “metal/rough” PBR workflow instead.

I’m not sure why UnityGLTF exports that, if it’s a current version of the software it may be worth filing a bug on the exporter.

Conversion of spec/gloss PBR to metal/rough PBR materials doesn’t take long, see the options in this post:

To summarize: open the file in https://gltf.report/, press OK at the prompt, then export from the right-hand panel.


Unrelated, but the model would also really benefit from draw call reduction, if you don’t need to interact with all of the objects separately. A quick solution for that would be:

npm install --global @gltf-transform/cli

gltf-transform optimize city.glb city+opt.glb --no-instance

Result:

city+metalrough+opt.glb (3.1 MB)

1 Like

Thanks for the detailed explanation. That worked for me.