Extensions

Extensions enhance a glTF Document with additional features and schema, beyond the core glTF specification. For example, extensions to Material properties might include additional textures or scalar properties affecting the Material's appearance in a specific way.

Common extensions may be imported from the @gltf-transform/extensions package, or custom extensions may be created by extending the Extension base class. No extensions are included in th default @gltf-transform/core package, in order to (1) minimize the code size, and (2) ensure that any extension can be implemented externally.

Because extensions rely on the same underlying graph structure as the core specification, references to Texture, Accessor, and other resources will be managed automatically, even by scripts or transforms written without prior knowledge of the extension. An extension is added to a Document by calling Document.createExtension with the extension constructor. The extension object may then be used to construct ExtensionProperty instances, which are attached to properties throughout the Document as prescribed by the extension itself.

Supported extensions:

Khronos Group:

Vendor:

Installation

To use extensions, first install the @gltf-transform/extensions package:

npm install --save @gltf-transform/extensions

To open files containing an Extension, the Extension constructor must be registered with the PlatformIO instance used to read the file.

// Register all Khronos Group (KHR_) extensions.
import { WebIO } from '@gltf-transform/core';
import { KHRONOS_EXTENSIONS } from '@gltf-transform/extensions';
const io = new WebIO().registerExtensions(KHRONOS_EXTENSIONS);

// Register an individual extension.
import { WebIO } from '@gltf-transform/core';
import { MaterialsUnlit } from '@gltf-transform/extensions';
const io = new WebIO().registerExtensions([MaterialsUnlit]);

// Read a file that requires the KHR_materials_unlit extension.
const doc = await io.readGLB('unlit.glb');

Reading files requires registering the necessary Extensions, but writing files does not — the Extension objects are already attached to the Document itself. Some extensions may require installing dependencies:

import { NodeIO } from '@gltf-transform/core';
import { KHRONOS_EXTENSIONS } from '@gltf-transform/extensions';

import * as draco3d from 'draco3dgltf';

const io = new NodeIO()
  .registerExtensions(KHRONOS_EXTENSIONS)
  .registerDependencies({
    'draco3d.decoder': draco3d.createDecoderModule(), // Optional.
    'draco3d.encoder': draco3d.createEncoderModule(), // Optional.
  });

const doc = io.read('compressed.glb');

API

When generating a glTF Document, import the Extension constructor and pass it to the Document.createExtension factory method.

import { Document } from '@gltf-transform/core';
import { MaterialsUnlit, Unlit } from '@gltf-transform/extensions';

// Create Document, and an instance of the KHR_materials_unlit extension.
const doc = new Document();
const unlitExtension = doc.createExtension(MaterialsUnlit).setRequired(false);

// Create a Material, and attach an Unlit property to it.
const unlit = unlitExtension.createUnlit();
doc.createMaterial('MyUnlitMaterial').setExtension('KHR_materials_unlit', unlit);

The Extension instance is then used to construct ExtensionProperty instances related to that Extension. Some Extensions, like KHR_mesh_quantization, have no Properties and simply have a holistic effect on the entire Document. Only one ExtensionProperty from a given Extension can be attached to any given Property at a time. Properties may have ExtensionProperties from multiple Extensions attached.

For further details on the general Extension API, see Extension and ExtensionProperty.

Custom extensions

In addition to the official Khronos and multi-vendor extensions, the glTF format can be extended with custom extensions for specific applications. glTF-Transform supports reading/writing custom extensions, without modifications to the core codebase. Any extension implemented correctly and registered with the I/O instance may be read from a file, modified programmatically, and written back to a file.

For implementation examples, see packages/extensions.

Supported extensions

KHR_draco_mesh_compression

The KHR_draco_mesh_compression extension provides advanced compression for mesh geometry. For models where geometry is a significant factor (>1 MB), Draco can reduce filesize by ~95% in many cases. When animation or textures are large, other complementary compression methods should be used as well. For geometry <1MB, the size of the WASM decoder library may outweigh size savings.

Be aware that decompression happens before uploading to the GPU — this will add some latency to the parsing process, and means that compressing geometry with Draco does not affect runtime performance. To improve framerate, you'll need to simplify the geometry by reducing vertex count or draw calls — not just compress it. Finally, be aware that Draco compression is lossy: repeatedly compressing and decompressing a model in a pipeline will lose precision, so compression should generally be the last stage of an art workflow, and uncompressed original files should be kept.

Currently, only reading KHR_draco_mesh_compression is supported, and output will always be uncompressed. Writing compressed data will be added at a later date, so for now use glTF-Pipeline for that. A decoder or encoder from draco3dgltf npm module is required for reading and writing respectively, and must be provided by the application:

import { NodeIO } from '@gltf-transform/core';
import { DracoMeshCompression } from '@gltf-transform/extensions';

import * as draco3d from 'draco3dgltf';

const io = new NodeIO()
  .registerExtensions([DracoMeshCompression])
  .registerDependencies({
    'draco3d.decoder': draco3d.createDecoderModule(),
    'draco3d.encoder': draco3d.createEncoderModule(),
  });

const doc = io.read('compressed.glb');

KHR_lights_punctual

The KHR_lights_punctual extension defines three "punctual" light types: directional, point and spot. Punctual lights are defined as parameterized, infinitely small points that emit light in well-defined directions and intensities. Lights are referenced by nodes and inherit the transform of that node.

import { LightsPunctual, Light, LightType } from '@gltf-transform/extensions';

// Create an Extension attached to the Document.
const lightsExtension = document.createExtension(LightsPunctual);

// Create a Light property.
const light = lightsExtension.createLight()
  .setType(LightType.POINT)
  .setIntensity(2.0)
  .setColor([1.0, 0.0, 0.0]);

// Attach the property to a Material.
node.setExtension('KHR_lights_punctual', light);

KHR_materials_clearcoat

The KHR_materials_clearcoat extension defines a clear coating that can be layered on top of an existing glTF material definition. A clear coat is a common technique used in Physically-Based Rendering to represent a protective layer applied to a base material.

The MaterialsClearcoat class provides a single ExtensionProperty type, Clearcoat, which may be attached to any Material instance. For example:

import { MaterialsClearcoat, Clearcoat } from '@gltf-transform/extensions';

// Create an Extension attached to the Document.
const clearcoatExtension = document.createExtension(MaterialsClearcoat);

// Create a Clearcoat property.
const clearcoat = clearcoatExtension.createClearcoat()
  .setClearcoatFactor(1.0);

// Attach the property to a Material.
material.setExtension('KHR_materials_clearcoat', clearcoat);

KHR_materials_ior (experimental)

The dielectric BRDF of the metallic-roughness material in glTF uses a fixed value of 1.5 for the index of refraction. This is a good fit for many plastics and glass, but not for other materials like water or asphalt, sapphire or diamond. KHR_materials_ior allows users to set the index of refraction to a certain value.

The MaterialsIOR class provides a single ExtensionProperty type, IOR, which may be attached to any Material instance. For example:

import { MaterialsIOR, IOR } from '@gltf-transform/extensions';

// Create an Extension attached to the Document.
const iorExtension = document.createExtension(MaterialsIOR);

// Create a IOR property.
const ior = iorExtension.createIOR().setIOR(1.0);

// Attach the property to a Material.
material.setExtension('KHR_materials_ior', ior);

KHR_materials_pbrSpecularGlossiness

KHR_materials_pbrSpecularGlossiness converts a PBR material from the default metal/rough workflow to a spec/gloss workflow. The spec/gloss workflow does not support other PBR extensions such as clearcoat, transmission, IOR, etc. For the complete PBR feature set and specular data, use the KHR_materials_specular extension instead of this one, which provides specular data within a metal/rough workflow.

The MaterialsPBRSpecularGlossiness class provides a single ExtensionProperty type, PBRSpecularGlossiness, which may be attached to any Material instance. For example:

import { MaterialsPBRSpecularGlossiness, PBRSpecularGlossiness } from '@gltf-transform/extensions';

// Create an Extension attached to the Document.
const specGlossExtension = document.createExtension(MaterialsPBRSpecularGlossiness);

// Create a PBRSpecularGlossiness property.
const specGloss = specGlossExtension.createPBRSpecularGlossiness()
  .setSpecularFactor(1.0);

// Attach the property to a Material.
material.setExtension('KHR_materials_pbrSpecularGlossiness', specGloss);

KHR_materials_sheen

KHR_materials_sheen defines a sheen that can be layered on top of an existing glTF material definition. A sheen layer is a common technique used in Physically-Based Rendering to represent cloth and fabric materials.

The MaterialsSheen class provides a single ExtensionProperty type, Sheen, which may be attached to any Material instance. For example:

import { MaterialsSheen, Sheen } from '@gltf-transform/extensions';

// Create an Extension attached to the Document.
const sheenExtension = document.createExtension(MaterialsSheen);

// Create a Sheen property.
const sheen = sheenExtension.createSheen()
  .setSheenColorFactor(1.0);

// Attach the property to a Material.
material.setExtension('KHR_materials_sheen', sheen);

KHR_materials_specular (experimental)

KHR_materials_specular allows users to configure the strength of the specular reflection in the dielectric BRDF. A value of zero disables the specular reflection, resulting in a pure diffuse material.

The MaterialsSpecular class provides a single ExtensionProperty type, Specular, which may be attached to any Material instance. For example:

import { MaterialsSpecular, Specular } from '@gltf-transform/extensions';

// Create an Extension attached to the Document.
const specularExtension = document.createExtension(MaterialsSpecular);

// Create a Specular property.
const specular = specularExtension.createSpecular()
  .setSpecularFactor(1.0);

// Attach the property to a Material.
material.setExtension('KHR_materials_specular', specular);

KHR_materials_transmission

The KHR_materials_transmission This extension aims to address the simplest and most common use cases for optical transparency: infinitely-thin materials with no refraction, scattering, or dispersion. When combined with KHR_materials_volume, transmission may be used for thicker materials and refractive effects.

The MaterialsTransmission class provides a single ExtensionProperty type, Transmission, which may be attached to any Material instance. For example:

import { MaterialsTransmission, Transmission } from '@gltf-transform/extensions';

// Create an Extension attached to the Document.
const transmissionExtension = document.createExtension(MaterialsTransmission);

// Create a Transmission property.
const transmission = transmissionExtension.createTransmission()
  .setTransmissionFactor(1.0);

// Attach the property to a Material.
material.setExtension('KHR_materials_transmission', transmission);

KHR_materials_unlit

The KHR_materials_unlit extension defines an unlit shading model for use in glTF 2.0 materials, as an alternative to the Physically Based Rendering (PBR) shading models provided by the core specification.

The MaterialsUnlit class provides a single ExtensionProperty type, Unlit, which may be attached to any Material instance. For example:

import { MaterialsUnlit, Unlit } from '@gltf-transform/extensions';

// Create an Extension attached to the Document.
const unlitExtension = document.createExtension(MaterialsUnlit);

// Create an Unlit property.
const unlit = unlitExtension.createUnlit();

// Attach the property to a Material.
material.setExtension('KHR_materials_unlit', unlit);

KHR_mesh_quantization

The KHR_mesh_quantization extension expands the set of allowed component types for mesh attribute storage to provide a memory/precision tradeoff — depending on the application needs, 16-bit or 8-bit storage can be sufficient.

Defining no ExtensionProperty types, this Extension is simply attached to the Document, and affects the entire Document by allowing more flexible use of Accessor types for vertex attributes. Without the Extension, the same use of these data types would yield an invalid glTF document, under the stricter core glTF specification.

import { MeshQuantization } from '@gltf-transform/extensions';

// Create an Extension attached to the Document.
const quantizationExtension = document.createExtension(MeshQuantization).setRequired(true);

KHR_texture_basisu

The KHR_texture_basisu extension adds the ability to use KTX2 GPU textures with Basis Universal supercompression for any material texture. GPU texture formats, unlike traditional image formats, remain compressed in GPU memory. As a result, they (1) upload to the GPU much more quickly, and (2) require much less GPU memory. In certain cases they may also have smaller filesizes than PNG or JPEG textures, but this is not guaranteed. GPU textures often require more careful tuning during compression to maintain image quality, but this extra effort is worthwhile for applications that need to maintain a smooth framerate while uploading images, or where GPU memory is limited.

Defining no ExtensionProperty types, this Extension is simply attached to the Document, and affects the entire Document by allowing use of the image/ktx2 MIME type and passing KTX2 image data to the Texture.setImage method. Without the Extension, the same MIME types and image data would yield an invalid glTF document, under the stricter core glTF specification.

import { TextureBasisu } from '@gltf-transform/extensions';

// Create an Extension attached to the Document.
const basisuExtension = document.createExtension(TextureBasisu)
  .setRequired(true);
document.createTexture('MyCompressedTexture')
  .setMimeType('image/ktx2')
  .setImage(fs.readFileSync('my-texture.ktx2'));

Compression is not done automatically when adding the extension as shown above — you must compress the image data first, then pass the .ktx2 payload to Texture.setImage. The glTF-Transform CLI has functions to help with this, or any similar KTX2-capable utility will work.

When the KHR_texture_basisu extension is added to a file by glTF-Transform, the extension should always be required. This tool does not support writing assets that "fall back" to optional PNG or JPEG image data.

NOTICE: Compressing some textures — particularly 3-component (RGB) normal maps, and occlusion/roughness/metalness maps, may give poor results with the ETC1S compression option. These issues can often be avoided with the larger UASTC compression option, or by upscaling the texture before compressing it.

For best results when authoring new textures, use texture dilation and minimize prominent UV seams.

KHR_texture_transform

The KHR_texture_transform extension adds offset, rotation, and scale to TextureInfo properties, applying an affine transform on the UV coordinates. UV transforms are useful for reducing the number of textures the GPU must load, improving performance when used in techniques like texture atlases. UV transforms cannot be animated at this time.

import { TextureTransform } from '@gltf-transform/extensions';

// Create an Extension attached to the Document.
const transformExtension = document.createExtension(TextureTransform)
  .setRequired(true);

// Create a reusable Transform.
const transform = transformExtension.createTransform()
  .setScale([100, 100]);

// Apply the Transform to a Material's baseColorTexture.
document.createMaterial()
  .setBaseColorTexture(myTexture)
  .getBaseColorTextureInfo()
  .setExtension('KHR_texture_transform', transform);

EXT_texture_webp

The EXT_texture_webp extension adds the ability to use WebP images for any material texture. WebP typically provides the smallest transmission size, but requires browser support. Like PNG and JPEG, a WebP image is fully decompressed when uploaded to the GPU, which increases upload time and GPU memory cost. For seamless uploads and minimal GPU memory cost, it is necessary to use a GPU texture format like Basis Universal, with the KHR_texture_basisu extension.

Defining no ExtensionProperty types, this Extension is simply attached to the Document, and affects the entire Document by allowing use of the image/webp MIME type and passing WebP image data to the Texture.setImage method. Without the Extension, the same MIME types and image data would yield an invalid glTF document, under the stricter core glTF specification.

import { TextureWebP } from '@gltf-transform/extensions';

// Create an Extension attached to the Document.
const webpExtension = document.createExtension(TextureWebP)
  .setRequired(true);
document.createTexture('MyWebPTexture')
  .setMimeType('image/webp')
  .setImage(fs.readFileSync('my-texture.webp'));

WebP conversion is not done automatically when adding the extension as shown above — you must convert the image data first, then pass the .webp payload to Texture.setImage.

When the EXT_texture_webp extension is added to a file by glTF-Transform, the extension should always be required. This tool does not support writing assets that "fall back" to optional PNG or JPEG image data.

Function symbol, f(📦) → 📦, where the argument and output are a box labeled 'glTF'.

Made by Don McCurdy TypeDoc documentation Copyright 2020 under MIT license