Support KHR_materials_unlit in Three.js GLTFLoader
This article explains how to parse and support the
KHR_materials_unlit extension when loading 3D models using
GLTFLoader in Three.js. It covers how Three.js handles
unlit materials automatically, provides a code implementation, and
explains how to verify that your unlit materials are rendering correctly
without light sources.
Automatic Support in GLTFLoader
In Three.js, GLTFLoader supports the
KHR_materials_unlit extension automatically out of the box.
You do not need to install additional plugins or manually register the
extension.
When GLTFLoader parses a glTF file containing the
KHR_materials_unlit extension, it automatically bypasses
the default physically-based rendering (PBR) material
(MeshStandardMaterial) and maps the affected materials to
MeshBasicMaterial. Because MeshBasicMaterial
does not react to light sources, it renders using only its flat color or
texture map, satisfying the “unlit” requirement.
Loading a Model with Unlit Materials
To load a model that utilizes the KHR_materials_unlit
extension, use the standard GLTFLoader implementation.
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
// Create scene, camera, and renderer
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Initialize GLTFLoader
const loader = new GLTFLoader();
// Load the glTF model
loader.load(
'path/to/unlit_model.gltf',
(gltf) => {
scene.add(gltf.scene);
console.log('Model loaded successfully!');
},
(xhr) => {
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
},
(error) => {
console.error('An error occurred while loading the model:', error);
}
);Because the materials are unlit, they will be visible in the scene
even if you do not add any light sources (such as
AmbientLight or DirectionalLight) to the
scene.
Verifying Unlit Materials Programmatically
If you need to verify that the loader has correctly parsed the
extension and applied MeshBasicMaterial, you can traverse
the loaded scene graph and inspect the materials of the meshes.
loader.load('path/to/unlit_model.gltf', (gltf) => {
gltf.scene.traverse((child) => {
if (child.isMesh) {
// Check if the material is an instance of MeshBasicMaterial
if (child.material.isMeshBasicMaterial) {
console.log(`Mesh "${child.name}" correctly uses an unlit material.`);
} else {
console.log(`Mesh "${child.name}" uses a standard lit material.`);
}
}
});
scene.add(gltf.scene);
});Creating Custom Fallbacks or Manual Handling
If you are writing custom shader materials or need to manually parse the extension from the raw glTF data, you can access the parser’s association data.
loader.load('path/to/unlit_model.gltf', (gltf) => {
const parser = gltf.parser;
gltf.scene.traverse((child) => {
if (child.isMesh) {
const materialIndex = parser.associations.get(child.material)?.materials;
if (materialIndex !== undefined) {
const gltfMaterialDef = parser.json.materials[materialIndex];
// Check if the glTF material definition uses the unlit extension
if (gltfMaterialDef.extensions && gltfMaterialDef.extensions.KHR_materials_unlit) {
// Apply custom behavior or shaders for unlit meshes here
}
}
}
});
});