Skip to main content

glTF Extension Support

Fromv9.3

This page summarizes the glTF extensions that @luma.gl/gltf handles in its default loader-to-scenegraph path. Each extension name links to its official Khronos-managed specification page in the glTF extension registry repository.

For a complete application walkthrough, including source JSON, public TypeScript APIs, real instanced draws, material selection, recursive mesh/light visibility, typed camera and light animation, capability diagnostics, and official sample coverage, see native glTF extensions.

Status meanings:

  • : works end-to-end in the default luma.gl glTF pipeline.
  • ✅ *️⃣: works in the default pipeline, with low-level decoding handled by @loaders.gl/gltf during load.
  • 🚧: work in progress for this release; implemented paths are still under active validation.
  • *️⃣: extension data is preserved or exposed, but applications still need to decide how to use it at runtime.
  • App: applications are responsible for selecting and applying the feature.
  • : no built-in handling today.
ExtensionSupportNotes
✅ *️⃣

@loaders.gl/gltf decompresses Draco meshes and converts them to regular glTF meshes.

✅ *️⃣

Meshopt-compressed primitives are decoded during load and converted to regular glTF meshes.

✅ *️⃣

Quantized accessors are unpacked during load before geometry creation.

Accessor-backed translation, rotation, and scale become one real instanced draw per source primitive on WebGL and WebGPU. Aggregate bounds include every instance, and application-defined _NAME attributes remain available.

Directional, point, and spot lights preserve authored intensity, range, source-node world transforms, and spotlight inner/outer cones. Use parseGLTFLights(gltf, {useByteColors: false}) for source-linear RGB colors.

Unlit materials bypass the default lighting calculations.

✅ 🚧

Emissive strength now multiplies the emissive contribution in the stock PBR shader.

✅ 🚧

The stock shader now applies specular intensity and color factors and textures to the dielectric F0 term.

✅ 🚧

The stock shader now drives dielectric reflectance from the glTF IOR value.

✅ 🚧

Material factors and textures are preserved. The shared experimental SceneRenderer and ANARI retained path refract captured opaque-scene color; the standalone glTF scenegraph path retains its alpha-based approximation.

✅ 🚧

Experimental, unratified proposal. Linear red-channel height textures perturb the existing tangent-space normal, preserve per-slot UV transforms, and compose with conventional normal maps.

✅ 🚧

Khronos release candidate, not ratified. Canonical WebGL and WebGPU PBR shading implements opposite-hemisphere punctual lighting and IBL, energy-conserving front-diffuse reduction, linear alpha factor maps, and sRGB transmission colors.

✅ 🚧

Thickness factor plus attenuation color and distance now tint transmitted light in the stock shader.

✅ 🚧

Authored dispersion is parsed into the canonical PBR material. Shared experimental and ANARI rendering separate transmitted RGB wavelengths using the ratified wavelength-dependent IOR. A supported material animation pointer can update the same physical dispersion uniform.

🚧

Active, unratified draft. A local thickness-aware, anisotropic single-scattering approximation is wired into diffuse transmission. Requires KHR_materials_volume; screen-space diffusion and random-walk multiple scattering are not implemented.

✅ 🚧

The stock shader now adds a secondary clearcoat lobe from the clearcoat and clearcoat-roughness inputs.

✅ 🚧

The stock shader now adds a sheen lobe using the sheen color and roughness inputs.

✅ 🚧

The stock shader now tints specular response with a view-dependent thin-film iridescence approximation driven by the extension inputs.

✅ 🚧

The stock shader now shapes highlights and IBL response with an anisotropy-direction approximation.

*️⃣

loaders.gl can preserve the extension data, but @luma.gl/gltf does not translate it into the default metallic-roughness shader path.

scenegraphs.variants.selectVariant(name) switches authored primitive materials without replacing scenegraph nodes; resetVariant() restores source defaults and pipeline state.

✅ *️⃣

BasisU / KTX2 textures are passed through as compressed textures when supported by the device.

✅ *️⃣

@loaders.gl/gltf resolves the texture source; runtime support still depends on browser and device decode support.

✅ *️⃣

Same as WebP: the source is resolved during load, with final support depending on decode support.

All 17 supported material slots retain independent offset, rotation, scale, and authored TEXCOORD_0 / TEXCOORD_1 selection.

✅ 🚧

Node TRS, morph-weight, and recursive boolean visibility pointers; selected material factor pointers; and animated KHR_texture_transform offset/rotation/scale pointers across all 17 supported slots are wired to runtime updates. Perspective/orthographic camera properties and typed punctual-light color, intensity, range, spotlight angles, and physical chromatic-dispersion factors are also supported. Boolean visibility uses authored STEP interpolation and refreshes punctual lights. Still unsupported: extras, structural material switches such as alphaMode / doubleSided / unlit, animated KHR_texture_transform.texCoord, and texture slots that resolve to TEXCOORD_2+. When used with KHR_materials_transmission / KHR_materials_volume, the shared experimental renderer and ANARI can refract captured scene color, while the standalone glTF scenegraph path still uses its alpha approximation.

Source-authored visibility recursively hides mesh descendants and punctual lights. Visibility-pointer animation updates existing scenegraph nodes and preserves the identity of the exported light array.

Metadata payloads remain in the loaded glTF, but luma.gl does not interpret them.

Metadata is available in the loaded glTF, but luma.gl does not interpret it.

Use loadPBREnvironment() or custom environment setup instead of relying on automatic extension handling. The current Khronos sample-asset catalog does not include an official EXT_lights_image_based sample.

Video textures are not created automatically by the glTF pipeline.

MSFT_lodFromv10.0

Animated crowds resolve authored node levels and MSFT_screencoverage thresholds, select independently animated actors by projected screen size, and compact each occupied mesh level into one instanced draw per primitive on WebGPU and WebGL 2. Optional index-only mesh decimation generates levels for assets that do not author them. Material-level LOD, GPU-driven selection, and progressive streaming are not implemented.

Inspect runtime capabilities

Source extension declarations can be inspected before scenegraph creation:

import {
assertSupportedGLTFExtensions,
createScenegraphsFromGLTF,
getGLTFExtensionSupport,
getUnsupportedRequiredGLTFExtensions
} from '@luma.gl/gltf';

for (const capability of getGLTFExtensionSupport(gltf).values()) {
console.log(capability.extensionName, {
required: capability.required,
supported: capability.supported,
level: capability.supportLevel,
explanation: capability.comment
});
}

const unsupportedRequired = getUnsupportedRequiredGLTFExtensions(gltf);

if (unsupportedRequired.length > 0) {
assertSupportedGLTFExtensions(gltf);
}

const scenegraphs = createScenegraphsFromGLTF(device, gltf, {
strictExtensions: true
});

built-in and parsed-and-wired capabilities satisfy required-extension checks. loader-only capabilities, including browser-dependent WebP and AVIF image decoding, do not promise complete portable runtime support. Unknown or none capabilities also fail when required. Optional unsupported extensions remain visible in the report without preventing scene creation.

The returned scenegraphs.extensionSupport preserves the document-specific capability report. Strict checks run before model creation, so an unsupported required feature does not leave a partially constructed GPU scene behind.

Use authored runtime extensions

import {getGLTFNodeInstancing} from '@luma.gl/gltf';

scenegraphs.variants.selectVariant('Midnight');
scenegraphs.variants.resetVariant();

const instancing = getGLTFNodeInstancing(gltf, gltf.nodes[0]);
console.log(instancing?.matrices.length);

scenegraphs.animator.selectClip('Night lighting', {
crossFadeDuration: 0.3
});
scenegraphs.animator.setTime(1000);

console.log(scenegraphs.cameras[0]);
console.log(scenegraphs.lights);

Variant selection preserves existing scenegraph node/model identities and restores unmapped primitives to their authored default materials. Instancing submits one GPU draw per source primitive on both WebGL and WebGPU. Visibility and punctual-light pointers update stable retained scene objects through the existing shared animation mixer. Automatic source skin palettes and morph targets are evaluated in the same frame.

Notes

  • getGLTFExtensionSupport(gltf) distinguishes optional and required extensions. Use getUnsupportedRequiredGLTFExtensions(gltf), assertSupportedGLTFExtensions(gltf), or createScenegraphsFromGLTF(device, gltf, {strictExtensions: true}) to reject unsupported required features instead of silently degrading them.
  • getGLTFNodeInstancing(gltf, node) exposes resolved source matrices and all authored instance-accessor semantics, including application-defined _NAME attributes.
  • The built-in material extension rows reuse the shared pbrMaterial shader. The experimental SceneRenderer and ANARI capture opaque scene color for screen-space transmission/refraction; the standalone createScenegraphsFromGLTF() rendering path does not perform that capture and retains its alpha fallback. Iridescence and anisotropy still use pragmatic shared-shader approximations.
  • The supported material extensions wire all 17 canonical core/extension texture slots, including auxiliary specular, clearcoat, sheen, iridescence, anisotropy, transmission, and volume maps. The physical response of some advanced effects remains an approximation.
  • @luma.gl/gltf relies on @loaders.gl/gltf for low-level extension decoding, decompression, and glTF post-processing.
  • Core glTF skin attributes and animated morph targets are supported independently of these extension rows; source skin palettes are updated automatically once per animation frame. See glTF animation and deformation, native glTF extensions, and glTF materials and textures.