@gltf-transform/functions
Version:
Functions for common glTF modifications, written using the core API
1,352 lines (1,351 loc) • 73.4 kB
TypeScript
import { Accessor, Document, GLTF, Material, Mesh, Node, Primitive, PrimitiveTarget, Property, PropertyResolver, Scene, Texture, TextureChannel, TextureInfo, Transform, TransformContext, TypedArray, bbox, mat4, vec2, vec3 } from "@gltf-transform/core";
//#region src/center.d.ts
/** Options for the {@link center} function. */
interface CenterOptions {
/** Location on the model to be considered the pivot, and recentered at the origin. */
pivot?: 'center' | 'above' | 'below' | vec3;
}
/**
* Centers the {@link Scene} at the origin, or above/below it. Transformations from animation,
* skinning, and morph targets are not taken into account.
*
* Example:
*
* ```ts
* await document.transform(center({pivot: 'below'}));
* ```
*
* @category Transforms
*/
declare function center(_options?: CenterOptions): Transform;
//#endregion
//#region src/clear-node-parent.d.ts
/**
* Clears the parent of the given {@link Node}, leaving it attached
* directly to its {@link Scene}. Inherited transforms will be applied
* to the Node. This operation changes the Node's local transform,
* but leaves its world transform unchanged.
*
* Example:
*
* ```typescript
* import { clearNodeParent } from '@gltf-transform/functions';
*
* scene.traverse((node) => { ... }); // Scene → … → Node
*
* clearNodeParent(node);
*
* scene.traverse((node) => { ... }); // Scene → Node
* ```
*
* To clear _all_ transforms of a Node, first clear its inherited transforms with
* {@link clearNodeParent}, then clear the local transform with {@link clearNodeTransform}.
*/
declare function clearNodeParent(node: Node): Node;
//#endregion
//#region src/clear-node-transform.d.ts
/**
* Clears local transform of the {@link Node}, applying the transform to children and meshes.
*
* - Applies transform to children
* - Applies transform to {@link Mesh mesh}
* - Resets {@link Light lights}, {@link Camera cameras}, and other attachments to the origin
*
* Example:
*
* ```typescript
* import { clearNodeTransform } from '@gltf-transform/functions';
*
* node.getTranslation(); // → [ 5, 0, 0 ]
* node.getMesh(); // → vertex data centered at origin
*
* clearNodeTransform(node);
*
* node.getTranslation(); // → [ 0, 0, 0 ]
* node.getMesh(); // → vertex data centered at [ 5, 0, 0 ]
* ```
*
* To clear _all_ transforms of a Node, first clear its inherited transforms with
* {@link clearNodeParent}, then clear the local transform with {@link clearNodeTransform}.
*/
declare function clearNodeTransform(node: Node): Node;
//#endregion
//#region src/compact-primitive.d.ts
/**
* Rewrites a {@link Primitive} such that all unused vertices in its vertex
* attributes are removed. When multiple Primitives share vertex attributes,
* each indexing only a few, compaction can be used to produce Primitives
* each having smaller, independent vertex streams instead.
*
* Regardless of whether the Primitive is indexed or contains unused vertices,
* compaction will clone every {@link Accessor}. The resulting Primitive will
* share no Accessors with other Primitives, allowing later changes to
* the vertex stream to be applied in isolation.
*
* Example:
*
* ```javascript
* import { compactPrimitive, transformMesh } from '@gltf-transform/functions';
* import { fromTranslation } from 'gl-matrix/mat4';
*
* const mesh = document.getRoot().listMeshes().find((mesh) => mesh.getName() === 'MyMesh');
* const prim = mesh.listPrimitives().find((prim) => { ... });
*
* // Compact primitive, removing unused vertices and detaching shared vertex
* // attributes. Without compaction, `transformPrimitive` might affect other
* // primitives sharing the same vertex attributes.
* compactPrimitive(prim);
*
* // Transform primitive vertices, y += 10.
* transformPrimitive(prim, fromTranslation([], [0, 10, 0]));
* ```
*
* Parameters 'remap' and 'dstVertexCount' are optional. When either is
* provided, the other must be provided as well. If one or both are missing,
* both will be computed from the mesh indices.
*
* @param remap - Mapping. Array index represents vertex index in the source
* attributes, array value represents index in the resulting compacted
* primitive. When omitted, calculated from indices.
* @param dstVertexcount - Number of unique vertices in compacted primitive.
* When omitted, calculated from indices.
*/
declare function compactPrimitive(prim: Primitive, remap?: TypedArray, dstVertexCount?: number): Primitive;
//#endregion
//#region src/convert-primitive-mode.d.ts
/**
* Converts a LINE_STRIP or LINE_LOOP {@link Primitive} to LINES, which is
* more widely supported. Any other topology given as input (points or
* triangles) will throw an error.
*
* Example:
*
* ```javascript
* import { convertPrimitiveToLines } from '@gltf-transform/functions';
*
* console.log(prim.getMode()); // 2 (LINE_LOOP)
* convertPrimitiveToLines(prim);
* console.log(prim.getMode()); // 1 (LINES)
* ```
*/
declare function convertPrimitiveToLines(prim: Primitive): void;
/**
* Converts a TRIANGLE_STRIP or TRIANGLE_LOOP {@link Primitive} to TRIANGLES,
* which is more widely supported. Any other topology given as input (points or
* lines) will throw an error.
*
* Example:
*
* ```javascript
* import { convertPrimitiveToTriangles } from '@gltf-transform/functions';
*
* console.log(prim.getMode()); // 5 (TRIANGLE_STRIP)
* convertPrimitiveToTriangles(prim);
* console.log(prim.getMode()); // 4 (TRIANGLES)
* ```
*/
declare function convertPrimitiveToTriangles(prim: Primitive): void;
//#endregion
//#region src/dedup.d.ts
interface DedupOptions {
/** Keep properties with unique names, even if they are duplicates. */
keepUniqueNames?: boolean;
/** List of {@link PropertyType} identifiers to be de-duplicated.*/
propertyTypes?: string[];
}
/**
* Removes duplicate {@link Accessor}, {@link Mesh}, {@link Texture}, and {@link Material}
* properties. Partially based on a
* [gist by mattdesl](https://gist.github.com/mattdesl/aea40285e2d73916b6b9101b36d84da8). Only
* accessors in mesh primitives, morph targets, and animation samplers are processed.
*
* Example:
*
* ```ts
* document.getRoot().listMeshes(); // → [Mesh, Mesh, Mesh]
*
* await document.transform(dedup({propertyTypes: [PropertyType.MESH]}));
*
* document.getRoot().listMeshes(); // → [Mesh]
* ```
*
* @category Transforms
*/
declare function dedup(_options?: DedupOptions): Transform;
//#endregion
//#region src/dequantize.d.ts
/** Options for the {@link dequantize} function. */
interface DequantizeOptions {
/**
* Pattern (regex) used to filter vertex attribute semantics for quantization.
* Default: `/^((?!JOINTS_).)*$/`.
*/
pattern?: RegExp;
}
/**
* Dequantize {@link Primitive Primitives}, removing {@link KHRMeshQuantization `KHR_mesh_quantization`}
* if present. Dequantization will increase the size of the mesh on disk and in memory, but may be
* necessary for compatibility with applications that don't support quantization.
*
* Example:
*
* ```javascript
* import { dequantizePrimitive } from '@gltf-transform/functions';
*
* await document.transform(dequantize());
* ```
*
* @category Transforms
*/
declare function dequantize(_options?: DequantizeOptions): Transform;
/**
* Dequantize a single {@link Primitive}, converting all vertex attributes to float32. Dequantization
* will increase the size of the mesh on disk and in memory, but may be necessary for compatibility
* with applications that don't support quantization.
*
* Example:
*
* ```javascript
* import { dequantizePrimitive } from '@gltf-transform/functions';
*
* const mesh = document.getRoot().listMeshes().find((mesh) => mesh.getName() === 'MyMesh');
*
* for (const prim of mesh.listPrimitives()) {
* dequantizePrimitive(prim);
* }
* ```
*/
declare function dequantizePrimitive(prim: Primitive, _options?: DequantizeOptions): void;
//#endregion
//#region src/document-utils.d.ts
/**
* Clones source {@link Document}, copying all properties and extensions within
* it. Source document remains unchanged, and the two may be modified
* independently after cloning.
*
* Example:
*
* ```javascript
* import { cloneDocument } from '@gltf-transform/functions';
*
* const targetDocument = cloneDocument(sourceDocument);
* ```
*/
declare function cloneDocument(source: Document): Document;
/**
* Merges contents of source {@link Document} into target Document, without
* modifying the source. Any extensions missing from the target will be added
* {@link Scene Scenes} and {@link Buffer Buffers} are not combined —
* the target Document may contain multiple Scenes and Buffers after this
* operation. These may be cleaned up manually (see {@link unpartition}),
* or document contents may be merged more granularly using
* {@link copyToDocument}.
*
* Example:
*
* ```javascript
* import { mergeDocuments, unpartition } from '@gltf-transform/functions';
*
* // Merge contents of sourceDocument into targetDocument.
* mergeDocuments(targetDocument, sourceDocument);
*
* // (Optional) Remove all but one Buffer from the target Document.
* await targetDocument.transform(unpartition());
* ```
*
* To merge several Scenes into one:
*
* ```javascript
* import { mergeDocuments } from '@gltf-transform/functions';
*
* const map = mergeDocuments(targetDocument, sourceDocument);
*
* // Find original Scene.
* const sceneA = targetDocument.getRoot().listScenes()[0];
*
* // Find counterpart of the source Scene in the target Document.
* const sceneB = map.get(sourceDocument.getRoot().listScenes()[0]);
*
* // Create a Node, and append source Scene's direct children.
* const rootNode = targetDocument.createNode()
* .setName('SceneB')
* .setPosition([10, 0, 0]);
* for (const node of sceneB.listChildren()) {
* rootNode.addChild(node);
* }
*
* // Append Node to original Scene, and dispose the empty Scene.
* sceneA.addChild(rootNode);
* sceneB.dispose();
* ```
*/
declare function mergeDocuments(target: Document, source: Document, resolve?: PropertyResolver<Property>): Map<Property, Property>;
/**
* Moves the specified {@link Property Properties} from the source
* {@link Document} to the target Document, and removes them from the source.
* Dependencies of the source properties will be copied into the
* target, but not removed from the source. Returns a Map from source
* properties to their counterparts in the target Document.
*
* Example:
*
* ```javascript
* import { moveToDocument, prune } from '@gltf-transform/functions';
*
* // Move all materials from sourceDocument to targetDocument.
* const map = moveToDocument(targetDocument, sourceDocument, sourceDocument.listMaterials());
*
* // Find the new counterpart of `sourceMaterial` in the target Document.
* const targetMaterial = map.get(sourceMaterial);
*
* // (Optional) Remove any resources (like Textures) that may now be unused
* // in the source Document after their parent Materials have been moved.
* await sourceDocument.transform(prune());
* ```
*
* Moving a {@link Mesh}, {@link Animation}, or another resource depending on
* a {@link Buffer} will create a copy of the source Buffer in the target
* Document. If the target Document should contain only one Buffer, call
* {@link unpartition} after moving properties.
*
* Repeated use of `moveToDocument` may create multiple copies of some
* resources, particularly shared dependencies like {@link Texture Textures} or
* {@link Accessor Accessors}. While duplicates can be cleaned up with
* {@link dedup}, it is also possible to prevent duplicates by creating and
* reusing the same resolver for all calls to `moveToDocument`:
*
* ```javascript
* import { moveToDocument, createDefaultPropertyResolver } from '@gltf-transform/functions';
*
* const resolve = createDefaultPropertyResolver(targetDocument, sourceDocument);
*
* // Move materials individually, without creating duplicates of shared textures.
* moveToDocument(targetDocument, sourceDocument, materialA, resolve);
* moveToDocument(targetDocument, sourceDocument, materialB, resolve);
* moveToDocument(targetDocument, sourceDocument, materialC, resolve);
* ```
*
* If the transferred properties include {@link ExtensionProperty ExtensionProperties},
* the associated {@link Extension Extensions} must be added to the target
* Document first:
*
* ```javascript
* for (const sourceExtension of source.getRoot().listExtensionsUsed()) {
* const targetExtension = target.createExtension(sourceExtension.constructor);
* if (sourceExtension.isRequired()) targetExtension.setRequired(true);
* }
* ```
*
* {@link Root} properties cannot be moved.
*
* {@link TextureInfo} properties cannot be given in the property list, but
* are handled automatically when moving a {@link Material}.
*
* To copy properties without removing them from the source Document, see
* {@link copyToDocument}.
*
* @experimental
*/
declare function moveToDocument(target: Document, source: Document, sourceProperties: Property[], resolve?: PropertyResolver<Property>): Map<Property, Property>;
/**
* Copies the specified {@link Property Properties} from the source
* {@link Document} to the target Document, leaving originals in the source.
* Dependencies of the source properties will also be copied into the
* target. Returns a Map from source properties to their counterparts in the
* target Document.
*
* Example:
*
* ```javascript
* import { copyToDocument } from '@gltf-transform/functions';
*
* // Copy all materials from sourceDocument to targetDocument.
* const map = copyToDocument(targetDocument, sourceDocument, sourceDocument.listMaterials());
*
* // Find the new counterpart of `sourceMaterial` in the target Document.
* const targetMaterial = map.get(sourceMaterial);
* ```
*
* Copying a {@link Mesh}, {@link Animation}, or another resource depending on
* a {@link Buffer} will create a copy of the source Buffer in the target
* Document. If the target Document should contain only one Buffer, call
* {@link unpartition} after copying properties.
*
* Repeated use of `copyToDocument` may create multiple copies of some
* resources, particularly shared dependencies like {@link Texture Textures} or
* {@link Accessor Accessors}. While duplicates can be cleaned up with
* {@link dedup}, it is also possible to prevent duplicates by creating and
* reusing the same resolver for all calls to `copyToDocument`:
*
* ```javascript
* import { copyToDocument, createDefaultPropertyResolver } from '@gltf-transform/functions';
*
* const resolve = createDefaultPropertyResolver(targetDocument, sourceDocument);
*
* // Copy materials individually, without creating duplicates of shared textures.
* copyToDocument(targetDocument, sourceDocument, materialA, resolve);
* copyToDocument(targetDocument, sourceDocument, materialB, resolve);
* copyToDocument(targetDocument, sourceDocument, materialC, resolve);
* ```
*
* If the transferred properties include {@link ExtensionProperty ExtensionProperties},
* the associated {@link Extension Extensions} must be added to the target
* Document first:
*
* ```javascript
* for (const sourceExtension of source.getRoot().listExtensionsUsed()) {
* const targetExtension = target.createExtension(sourceExtension.constructor);
* if (sourceExtension.isRequired()) targetExtension.setRequired(true);
* }
* ```
*
* {@link Root} properties cannot be copied.
*
* {@link TextureInfo} properties cannot be given in the property list, but
* are handled automatically when copying a {@link Material}.
*
* To move properties to the target Document without leaving copies behind in
* the source Document, use {@link moveToDocument} or dispose the properties
* after copying.
*
* @experimental
*/
declare function copyToDocument(target: Document, source: Document, sourceProperties: Property[], resolve?: PropertyResolver<Property>): Map<Property, Property>;
/**
* Creates a default `resolve` implementation. May be used when moving
* properties between {@link Document Documents} with {@link mergeDocuments},
* {@link copyToDocument}, and {@link moveToDocument}. When the same resolver
* is passed to multiple invocations, these functions will reuse previously-
* transferred resources.
*
* @experimental
*/
declare function createDefaultPropertyResolver(target: Document, source: Document): PropertyResolver<Property>;
//#endregion
//#region src/draco.d.ts
interface DracoOptions {
method?: 'edgebreaker' | 'sequential';
encodeSpeed?: number;
decodeSpeed?: number;
quantizePosition?: number;
quantizeNormal?: number;
quantizeColor?: number;
quantizeTexcoord?: number;
quantizeGeneric?: number;
quantizationVolume?: 'mesh' | 'scene';
}
declare const DRACO_DEFAULTS: Required<DracoOptions>;
/**
* Applies Draco compression using {@link KHRDracoMeshCompression KHR_draco_mesh_compression}.
* Draco compression can reduce the size of triangle geometry.
*
* This function is a thin wrapper around the {@link KHRDracoMeshCompression} extension.
*
* ### Example
*
* ```typescript
* import { NodeIO } from '@gltf-transform/core';
* import { KHRDracoMeshCompression } from '@gltf-transform/extensions';
* import { draco } from '@gltf-transform/functions';
* import draco3d from 'draco3dgltf';
*
* const io = new NodeIO()
* .registerExtensions([KHRDracoMeshCompression])
* .registerDependencies({
* 'draco3d.encoder': await draco3d.createEncoderModule()
* });
*
* await document.transform(
* draco({method: 'edgebreaker'})
* );
*
* await io.write('compressed.glb', document);
* ```
*
* Compression is deferred until generating output with an I/O class.
*
* @category Transforms
*/
declare function draco(_options?: DracoOptions): Transform;
//#endregion
//#region src/flatten.d.ts
/** Options for the {@link flatten} function. */
interface FlattenOptions {
/**
* Whether to perform cleanup steps after completing the operation. Recommended, and enabled by
* default. Cleanup removes temporary resources created during the operation, but may also remove
* pre-existing unused or duplicate resources in the {@link Document}. Applications that require
* keeping these resources may need to disable cleanup, instead calling {@link dedup} and
* {@link prune} manually (with customized options) later in the processing pipeline.
* @experimental
*/
cleanup?: boolean;
}
declare const FLATTEN_DEFAULTS: Required<FlattenOptions>;
/**
* Flattens the scene graph, leaving {@link Node Nodes} with
* {@link Mesh Meshes}, {@link Camera Cameras}, and other attachments
* as direct children of the {@link Scene}. Skeletons and their
* descendants are left in their original Node structure.
*
* {@link Animation} targeting a Node or its parents will
* prevent that Node from being moved.
*
* Example:
*
* ```ts
* import { flatten } from '@gltf-transform/functions';
*
* await document.transform(flatten());
* ```
*
* @category Transforms
*/
declare function flatten(_options?: FlattenOptions): Transform;
//#endregion
//#region src/get-bounds.d.ts
/**
* Computes bounding box (AABB) in world space for the given {@link Node} or {@link Scene}.
*
* Example:
*
* ```ts
* import { getBounds } from '@gltf-transform/functions';
*
* const {min, max} = getBounds(scene);
* ```
*/
declare function getBounds(node: Node | Scene): bbox;
//#endregion
//#region src/get-texture-color-space.d.ts
/**
* Returns the color space (if any) implied by the {@link Material} slots to
* which a texture is assigned, or null for non-color textures. If the texture
* is not connected to any {@link Material}, this function will also return
* null — any metadata in the image file will be ignored.
*
* Under current glTF specifications, only 'srgb' and non-color (null) textures
* are used.
*
* Example:
*
* ```typescript
* import { getTextureColorSpace } from '@gltf-transform/functions';
*
* const baseColorTexture = material.getBaseColorTexture();
* const normalTexture = material.getNormalTexture();
*
* getTextureColorSpace(baseColorTexture); // → 'srgb'
* getTextureColorSpace(normalTexture); // → null
* ```
*/
declare function getTextureColorSpace(texture: Texture): 'srgb' | null;
//#endregion
//#region src/get-vertex-count.d.ts
/**
* Various methods of estimating a vertex count. For some background on why
* multiple definitions of a vertex count should exist, see [_Vertex Count
* Higher in Engine than in 3D Software_](https://shahriyarshahrabi.medium.com/vertex-count-higher-in-engine-than-in-3d-software-badc348ada66).
* Totals for a {@link Scene}, {@link Node}, or {@link Mesh} will not
* necessarily match the sum of the totals for each {@link Primitive}. Choose
* the appropriate method for a relevant total or estimate:
*
* - {@link getSceneVertexCount}
* - {@link getNodeVertexCount}
* - {@link getMeshVertexCount}
* - {@link getPrimitiveVertexCount}
*
* Many rendering features, such as volumetric transmission, may lead
* to additional passes over some or all vertices. These tradeoffs are
* implementation-dependent, and not considered here.
*/
declare enum VertexCountMethod {
/**
* Expected number of vertices processed by the vertex shader for one render
* pass, without considering the vertex cache.
*/
RENDER = "render",
/**
* Expected number of vertices processed by the vertex shader for one render
* pass, assuming an Average Transform to Vertex Ratio (ATVR) of 1. Approaching
* this result requires optimizing for locality of vertex references (see
* {@link reorder}).
*
* References:
* - [ACMR and ATVR](https://www.realtimerendering.com/blog/acmr-and-atvr/), Real-Time Rendering
*/
RENDER_CACHED = "render-cached",
/**
* Expected number of vertices uploaded to the GPU, assuming that a client
* uploads each unique {@link Accessor} only once. Unless glTF vertex
* attributes are pre-processed to a known buffer layout, and the client is
* optimized for that buffer layout, this total will be optimistic.
*/
UPLOAD = "upload",
/**
* Expected number of vertices uploaded to the GPU, assuming that a client
* uploads each unique {@link Primitive} individually, duplicating vertex
* attribute {@link Accessor Accessors} shared by multiple primitives, but
* never uploading the same Mesh or Primitive to GPU memory more than once.
*/
UPLOAD_NAIVE = "upload-naive",
/**
* Number of vertex positions never used by any {@link Primitive}. If all
* vertices are unused, this total will match `UPLOAD`.
*/
UNUSED = "unused"
}
/**
* Computes total number of vertices in a {@link Scene}, by the
* specified method. Totals for the Scene will not necessarily match the sum
* of the totals for each {@link Mesh} or {@link Primitive} within it. See
* {@link VertexCountMethod} for available methods.
*/
declare function getSceneVertexCount(scene: Scene, method: VertexCountMethod): number;
/**
* Computes total number of vertices in a {@link Node}, by the
* specified method. Totals for the node will not necessarily match the sum
* of the totals for each {@link Mesh} or {@link Primitive} within it. See
* {@link VertexCountMethod} for available methods.
*/
declare function getNodeVertexCount(node: Node | Scene, method: VertexCountMethod): number;
/**
* Computes total number of vertices in a {@link Mesh}, by the
* specified method. Totals for the Mesh will not necessarily match the sum
* of the totals for each {@link Primitive} within it. See
* {@link VertexCountMethod} for available methods.
*/
declare function getMeshVertexCount(mesh: Mesh, method: VertexCountMethod): number;
/**
* Computes total number of vertices in a {@link Primitive}, by the
* specified method. See {@link VertexCountMethod} for available methods.
*/
declare function getPrimitiveVertexCount(prim: Primitive, method: VertexCountMethod): number;
//#endregion
//#region src/inspect.d.ts
/** Inspects the contents of a glTF file and returns a JSON report. */
declare function inspect(doc: Document): InspectReport;
interface InspectReport {
scenes: InspectPropertyReport<InspectSceneReport>;
meshes: InspectPropertyReport<InspectMeshReport>;
materials: InspectPropertyReport<InspectMaterialReport>;
textures: InspectPropertyReport<InspectTextureReport>;
animations: InspectPropertyReport<InspectAnimationReport>;
}
interface InspectPropertyReport<T> {
properties: T[];
errors?: string[];
warnings?: string[];
}
interface InspectSceneReport {
name: string;
rootName: string;
bboxMin: number[];
bboxMax: number[];
renderVertexCount: number;
uploadVertexCount: number;
uploadNaiveVertexCount: number;
}
interface InspectMeshReport {
name: string;
meshPrimitives: number;
mode: string[];
vertices: number;
glPrimitives: number;
indices: string[];
attributes: string[];
instances: number;
size: number;
}
interface InspectMaterialReport {
name: string;
instances: number;
textures: string[];
alphaMode: GLTF.MaterialAlphaMode;
doubleSided: boolean;
}
interface InspectTextureReport {
name: string;
uri: string;
slots: string[];
instances: number;
mimeType: string;
resolution: string;
compression: string;
size: number;
gpuSize: number | null;
}
interface InspectAnimationReport {
name: string;
channels: number;
samplers: number;
keyframes: number;
duration: number;
size: number;
}
//#endregion
//#region src/instance.d.ts
interface InstanceOptions {
/** Minimum number of meshes considered eligible for instancing. Default: 5. */
min?: number;
}
declare const INSTANCE_DEFAULTS: Required<InstanceOptions>;
/**
* Creates GPU instances (with {@link EXTMeshGPUInstancing}) for shared {@link Mesh} references. In
* engines supporting the extension, reused Meshes will be drawn with GPU instancing, greatly
* reducing draw calls and improving performance in many cases. If you're not sure that identical
* Meshes share vertex data and materials ("linked duplicates"), run {@link dedup} first to link them.
*
* Example:
*
* ```javascript
* import { dedup, instance } from '@gltf-transform/functions';
*
* await document.transform(
* dedup(),
* instance({min: 5}),
* );
* ```
*
* @category Transforms
*/
declare function instance(_options?: InstanceOptions): Transform;
//#endregion
//#region src/join.d.ts
/** Options for the {@link join} function. */
interface JoinOptions {
/**
* Prevents joining distinct {@link Mesh Meshes} and {@link Node Nodes}.
* Joins only Primitives found within the same parent Mesh. To preserve
* only _named_ Nodes and Meshes, use
* {@link JoinOptions.keepNamed keepNamed} instead. Default: false.
*/
keepMeshes?: boolean;
/**
* Prevents joining _named_ {@link Mesh Meshes} and {@link Node Nodes}.
* If {@link JoinOptions.keepMeshes keepMeshes} is enabled, keepNamed will
* have no effect. Default: false.
*/
keepNamed?: boolean;
/**
* Whether to perform cleanup steps after completing the operation. Recommended, and enabled by
* default. Cleanup removes temporary resources created during the operation, but may also remove
* pre-existing unused or duplicate resources in the {@link Document}. Applications that require
* keeping these resources may need to disable cleanup, instead calling {@link dedup} and
* {@link prune} manually (with customized options) later in the processing pipeline.
* @experimental
*/
cleanup?: boolean;
/**
* A filter function used to evaluate a condition on a given {@link Node Node}.
* This function should return a boolean indicating whether the node
* satisfies the provided condition.
*
* @param {Node} node - The node instance to be evaluated.
* @returns {boolean} - The result of the evaluation; `true` if the condition is met, otherwise `false`.
*/
filter?: (node: Node) => boolean;
}
declare const JOIN_DEFAULTS: Required<JoinOptions>;
/**
* Joins compatible {@link Primitive Primitives} and reduces draw calls.
* Primitives are eligible for joining if they are members of the same
* {@link Mesh} or, optionally, attached to sibling {@link Node Nodes}
* in the scene hierarchy. For best results, apply {@link dedup} and
* {@link flatten} first to maximize the number of Primitives that
* can be joined.
*
* NOTE: In a Scene that heavily reuses the same Mesh data, joining may
* increase vertex count. Consider alternatives, like
* {@link instance instancing} with {@link EXTMeshGPUInstancing}.
*
* Example:
*
* ```ts
* import { PropertyType } from '@gltf-transform/core';
* import { join, flatten, dedup } from '@gltf-transform/functions';
*
* await document.transform(
* dedup({ propertyTypes: [PropertyType.MATERIAL] }),
* flatten(),
* join({ keepNamed: false }),
* );
* ```
*
* @category Transforms
*/
declare function join(_options?: JoinOptions): Transform;
//#endregion
//#region src/join-primitives.d.ts
interface JoinPrimitiveOptions {
skipValidation?: boolean;
}
/**
* Given a list of compatible Mesh {@link Primitive Primitives}, returns new Primitive
* containing their vertex data. Compatibility requires that all Primitives share the
* same {@link Material Materials}, draw mode, and vertex attribute types. Primitives
* using morph targets cannot currently be joined.
*
* Example:
*
* ```javascript
* import { joinPrimitives } from '@gltf-transform/functions';
*
* // Succeeds if Primitives are compatible, or throws an error.
* const result = joinPrimitives(mesh.listPrimitives());
*
* for (const prim of mesh.listPrimitives()) {
* prim.dispose();
* }
*
* mesh.addPrimitive(result);
* ```
*/
declare function joinPrimitives(prims: Primitive[], _options?: JoinPrimitiveOptions): Primitive;
//#endregion
//#region src/list-node-scenes.d.ts
/**
* Finds the parent {@link Scene Scenes} associated with the given {@link Node}.
* In most cases a Node is associated with only one Scene, but it is possible
* for a Node to be located in two or more Scenes, or none at all.
*
* Example:
*
* ```typescript
* import { listNodeScenes } from '@gltf-transform/functions';
*
* const node = document.getRoot().listNodes()
* .find((node) => node.getName() === 'MyNode');
*
* const scenes = listNodeScenes(node);
* ```
*/
declare function listNodeScenes(node: Node): Scene[];
//#endregion
//#region src/list-texture-channels.d.ts
/**
* Returns a list of {@link TextureChannel TextureChannels} used by the given
* texture. Determination is based only on the _role_ of the textures, e.g.
* a texture used for the `occlusionTexture` will have (at least) a red channel
* in use. See {@link getTextureChannelMask} for bitmask alternative.
*
* Example:
*
* ```js
* const channels = listTextureChannels(texture);
* if (channels.includes(TextureChannel.R)) {
* console.log('texture red channel used');
* }
* ```
*/
declare function listTextureChannels(texture: Texture): TextureChannel[];
/**
* Returns bitmask of all {@link TextureChannel TextureChannels} used by the
* given texture. Determination is based only on the _role_ of the textures, e.g.
* a texture used for the `occlusionTexture` will have (at least) a red channel.
* See {@link listTextureChannels} for an array alternative.
*
* Example:
*
* ```js
* const mask = getTextureChannelMask(texture);
* if (mask & TextureChannel.R) {
* console.log('texture red channel used');
* }
* ```
*/
declare function getTextureChannelMask(texture: Texture): number;
//#endregion
//#region src/list-texture-info.d.ts
/**
* Lists all {@link TextureInfo} definitions associated with a given
* {@link Texture}. May be used to determine which UV transforms
* and texCoord indices are applied to the material, without explicitly
* checking the material properties and extensions.
*
* Example:
*
* ```typescript
* // Find TextureInfo instances associated with the texture.
* const results = listTextureInfo(texture);
*
* // Find which UV sets (TEXCOORD_0, TEXCOORD_1, ...) are required.
* const texCoords = results.map((info) => info.getTexCoord());
* // → [0, 1]
* ```
*/
declare function listTextureInfo(texture: Texture): TextureInfo[];
/**
* Lists all {@link TextureInfo} definitions associated with any {@link Texture}
* on the given {@link Material}. May be used to determine which UV transforms
* and texCoord indices are applied to the material, without explicitly
* checking the material properties and extensions.
*
* Example:
*
* ```typescript
* const results = listTextureInfoByMaterial(material);
*
* const texCoords = results.map((info) => info.getTexCoord());
* // → [0, 1]
* ```
*/
declare function listTextureInfoByMaterial(material: Material): TextureInfo[];
//#endregion
//#region src/list-texture-slots.d.ts
/**
* Returns names of all texture slots using the given texture.
*
* Example:
*
* ```js
* const slots = listTextureSlots(texture);
* // → ['occlusionTexture', 'metallicRoughnessTexture']
* ```
*/
declare function listTextureSlots(texture: Texture): string[];
//#endregion
//#region src/quantize.d.ts
/** Options for the {@link quantize} function. */
interface QuantizeOptions {
/** Pattern (regex) used to filter vertex attribute semantics for quantization. Default: all. */
pattern?: RegExp;
/** Pattern (regex) used to filter morph target semantics for quantization. Default: `options.pattern`. */
patternTargets?: RegExp;
/** Bounds for quantization grid. */
quantizationVolume?: 'mesh' | 'scene';
/** Quantization bits for `POSITION` attributes. */
quantizePosition?: number;
/** Quantization bits for `NORMAL` attributes. */
quantizeNormal?: number;
/** Quantization bits for `TEXCOORD_*` attributes. */
quantizeTexcoord?: number;
/** Quantization bits for `COLOR_*` attributes. */
quantizeColor?: number;
/** Quantization bits for `WEIGHT_*` attributes. */
quantizeWeight?: number;
/** Quantization bits for application-specific (`_*`) attributes. */
quantizeGeneric?: number;
/** Normalize weight attributes. */
normalizeWeights?: boolean;
/**
* Whether to perform cleanup steps after completing the operation. Recommended, and enabled by
* default. Cleanup removes temporary resources created during the operation, but may also remove
* pre-existing unused or duplicate resources in the {@link Document}. Applications that require
* keeping these resources may need to disable cleanup, instead calling {@link dedup} and
* {@link prune} manually (with customized options) later in the processing pipeline.
* @experimental
*/
cleanup?: boolean;
}
declare const QUANTIZE_DEFAULTS: Required<Omit<QuantizeOptions, 'patternTargets'>>;
/**
* References:
* - https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_mesh_quantization
* - http://www.aclockworkberry.com/normal-unpacking-quantization-errors/
* - https://www.mathworks.com/help/dsp/ref/uniformencoder.html
* - https://oroboro.com/compressed-unit-vectors/
*/
/**
* Quantizes vertex attributes with `KHR_mesh_quantization`, reducing the size and memory footprint
* of the file. Conceptually, quantization refers to snapping values to regular intervals; vertex
* positions are snapped to a 3D grid, UVs to a 2D grid, and so on. When quantized to <= 16 bits,
* larger component types may be more compactly stored as 16-bit or 8-bit attributes.
*
* Often, it can be useful to quantize to precision lower than the maximum allowed by the component
* type. Positions quantized to 14 bits in a 16-bit accessor will occupy 16 bits in VRAM, but they
* can be compressed further for network compression with lossless encodings such as ZSTD.
*
* Vertex positions are shifted into [-1,1] or [0,1] range before quantization. Compensating for
* that shift, a transform is applied to the parent {@link Node}, or inverse bind matrices for a
* {@link Skin} if applicable. Materials using {@link KHRMaterialsVolume} are adjusted to maintain
* appearance. In future releases, UVs may also be transformed with {@link KHRTextureTransform}.
* Currently UVs outside of [0,1] range are not quantized.
*
* In most cases, quantization requires {@link KHRMeshQuantization}; the extension will be added
* automatically when `quantize()` is applied. When applying meshopt compression with
* {@link EXTMeshoptCompression}, quantization is usually applied before compression.
*
* Example:
*
* ```javascript
* import { quantize } from '@gltf-transform/functions';
*
* await document.transform(
* quantize({
* quantizePosition: 14,
* quantizeNormal: 10,
* }),
* );
* ```
*
* For the inverse operation, see {@link dequantize}.
*
* @category Transforms
*/
declare function quantize(_options?: QuantizeOptions): Transform;
//#endregion
//#region src/meshopt.d.ts
interface MeshoptOptions extends Omit<QuantizeOptions, 'pattern' | 'patternTargets'> {
encoder: unknown;
level?: 'medium' | 'high';
}
declare const MESHOPT_DEFAULTS: Required<Omit<MeshoptOptions, 'encoder'>>;
/**
* Applies Meshopt compression using {@link EXTMeshoptCompression EXT_meshopt_compression}.
* This type of compression can reduce the size of point, line, and triangle geometry,
* morph targets, and animation data.
*
* This function is a thin wrapper around {@link reorder}, {@link quantize}, and
* {@link EXTMeshoptCompression}, and exposes relatively few configuration options.
* To access more options (like quantization bits) direct use of the underlying
* functions is recommended.
*
* Example:
*
* ```javascript
* import { MeshoptEncoder } from 'meshoptimizer';
* import { meshopt } from '@gltf-transform/functions';
*
* await MeshoptEncoder.ready;
*
* await document.transform(
* meshopt({encoder: MeshoptEncoder, level: 'medium'})
* );
* ```
*
* Compression is deferred until generating output with an I/O class.
*
* @category Transforms
*/
declare function meshopt(_options: MeshoptOptions): Transform;
//#endregion
//#region src/metal-rough.d.ts
interface MetalRoughOptions {}
/**
* Convert {@link Material}s from spec/gloss PBR workflow to metal/rough PBR workflow,
* removing `KHR_materials_pbrSpecularGlossiness` and adding `KHR_materials_ior` and
* `KHR_materials_specular`. The metal/rough PBR workflow is preferred for most use cases,
* and is a prerequisite for other advanced PBR extensions provided by glTF.
*
* No options are currently implemented for this function.
*
* @category Transforms
*/
declare function metalRough(_options?: MetalRoughOptions): Transform;
//#endregion
//#region src/normals.d.ts
/** Options for the {@link normals} function. */
interface NormalsOptions {
/** Whether to overwrite existing `NORMAL` attributes. */
overwrite?: boolean;
}
/**
* Generates flat vertex normals for mesh primitives.
*
* Example:
*
* ```ts
* import { normals } from '@gltf-transform/functions';
*
* await document.transform(normals({overwrite: true}));
* ```
*
* @category Transforms
*/
declare function normals(_options?: NormalsOptions): Transform;
//#endregion
//#region src/palette.d.ts
interface PaletteOptions {
/** Size (in pixels) of a single block within each palette texture. Default: 4. */
blockSize?: number;
/**
* Minimum number of blocks in the palette texture. If fewer unique
* material values are found, no palettes will be generated. Default: 5.
*/
min?: number;
/**
* Whether to keep unused vertex attributes, such as UVs without an assigned
* texture. If kept, unused UV coordinates may prevent palette texture
* creation. Default: false.
*/
keepAttributes?: boolean;
/**
* Whether to perform cleanup steps after completing the operation. Recommended, and enabled by
* default. Cleanup removes temporary resources created during the operation, but may also remove
* pre-existing unused or duplicate resources in the {@link Document}. Applications that require
* keeping these resources may need to disable cleanup, instead calling {@link dedup} and
* {@link prune} manually (with customized options) later in the processing pipeline.
* @experimental
*/
cleanup?: boolean;
}
declare const PALETTE_DEFAULTS: Required<PaletteOptions>;
/**
* Creates palette textures containing all unique values of scalar
* {@link Material} properties within the scene, then merges materials. For
* scenes with many solid-colored materials (often found in CAD, architectural,
* or low-poly styles), texture palettes can reduce the number of materials
* used, and significantly increase the number of {@link Mesh} objects eligible
* for {@link join} operations.
*
* Materials already containing texture coordinates (UVs) are not eligible for
* texture palette optimizations. Currently only a material's base color,
* alpha, emissive factor, metallic factor, and roughness factor are converted
* to palette textures.
*
* Example:
*
* ```typescript
* import { palette, flatten, dequantize, join } from '@gltf-transform/functions';
*
* await document.transform(
* palette({ min: 5 }),
* flatten(),
* dequantize(),
* join()
* );
* ```
*
* The illustration below shows a typical base color palette texture:
*
* <img
* src="/media/functions/palette.png"
* alt="Row of colored blocks"
* style="width: 100%; max-width: 320px; image-rendering: pixelated;">
*
* @category Transforms
*/
declare function palette(_options?: PaletteOptions): Transform;
//#endregion
//#region src/partition.d.ts
interface PartitionOptions {
animations?: boolean | Array<string>;
meshes?: boolean | Array<string>;
}
/**
* Partitions the binary payload of a glTF file so separate mesh or animation data is in separate
* `.bin` {@link Buffer}s. This technique may be useful for engines that support lazy-loading
* specific binary resources as needed over the application lifecycle.
*
* Example:
*
* ```ts
* document.getRoot().listBuffers(); // → [Buffer]
*
* await document.transform(partition({meshes: true}));
*
* document.getRoot().listBuffers(); // → [Buffer, Buffer, ...]
* ```
*
* @category Transforms
*/
declare function partition(_options?: PartitionOptions): Transform;
//#endregion
//#region src/prune.d.ts
interface PruneOptions {
/** List of {@link PropertyType} identifiers to be de-duplicated.*/
propertyTypes?: string[];
/** Whether to keep empty leaf nodes. */
keepLeaves?: boolean;
/** Whether to keep unused vertex attributes, such as UVs without an assigned texture. */
keepAttributes?: boolean;
/**
* Whether to keep redundant mesh indices, where vertex count equals index count.
* @deprecated Disabled. To remove indices, use {@link unweld} or other APIs.
* @privateRemarks TODO(v5): Remove this option.
*/
keepIndices?: boolean;
/** Whether to keep single-color textures that can be converted to material factors. */
keepSolidTextures?: boolean;
/** Whether custom extras should prevent pruning a property. */
keepExtras?: boolean;
}
declare const PRUNE_DEFAULTS: Required<PruneOptions>;
/**
* Removes properties from the file if they are not referenced by a {@link Scene}. Commonly helpful
* for cleaning up after other operations, e.g. allowing a node to be detached and any unused
* meshes, materials, or other resources to be removed automatically.
*
* Example:
*
* ```javascript
* import { PropertyType } from '@gltf-transform/core';
* import { prune } from '@gltf-transform/functions';
*
* document.getRoot().listMaterials(); // → [Material, Material]
*
* await document.transform(
* prune({
* propertyTypes: [PropertyType.MATERIAL],
* keepExtras: true
* })
* );
*
* document.getRoot().listMaterials(); // → [Material]
* ```
*
* By default, pruning will aggressively remove most unused resources. Use
* {@link PruneOptions} to limit what is considered for pruning.
*
* @category Transforms
*/
declare function prune(_options?: PruneOptions): Transform;
//#endregion
//#region src/reorder.d.ts
/** Options for the {@link reorder} function. */
interface ReorderOptions {
/** MeshoptEncoder instance. */
encoder: unknown;
/**
* Whether the order should be optimal for transmission size (recommended for Web)
* or for GPU rendering performance. Default is 'size'.
*/
target?: 'size' | 'performance';
/**
* Whether to perform cleanup steps after completing the operation. Recommended, and enabled by
* default. Cleanup removes temporary resources created during the operation, but may also remove
* pre-existing unused or duplicate resources in the {@link Document}. Applications that require
* keeping these resources may need to disable cleanup, instead calling {@link dedup} and
* {@link prune} manually (with customized options) later in the processing pipeline.
* @experimental
*/
cleanup?: boolean;
}
/**
* Optimizes {@link Mesh} {@link Primitive Primitives} for locality of reference. Choose whether
* the order should be optimal for transmission size (recommended for Web) or for GPU rendering
* performance. Requires a MeshoptEncoder instance from the Meshoptimizer library.
*
* Example:
*
* ```ts
* import { MeshoptEncoder } from 'meshoptimizer';
* import { reorder } from '@gltf-transform/functions';
*
* await MeshoptEncoder.ready;
*
* await document.transform(
* reorder({encoder: MeshoptEncoder})
* );
* ```
*
* @category Transforms
*/
declare function reorder(_options: ReorderOptions): Transform;
//#endregion
//#region src/resample.d.ts
interface ResampleOptions {
ready?: Promise<void>;
resample?: unknown;
tolerance?: number;
/**
* Whether to perform cleanup steps after completing the operation. Recommended, and enabled by
* default. Cleanup removes temporary resources created during the operation, but may also remove
* pre-existing unused or duplicate resources in the {@link Document}. Applications that require
* keeping these resources may need to disable cleanup, instead calling {@link dedup} and
* {@link prune} manually (with customized options) later in the processing pipeline.
* @experimental
*/
cleanup?: boolean;
}
/**
* Resample {@link AnimationChannel AnimationChannels}, losslessly deduplicating keyframes to
* reduce file size. Duplicate keyframes are commonly present in animation 'baked' by the
* authoring software to apply IK constraints or other software-specific features.
*
* Optionally, a WebAssembly implementation from the
* [`keyframe-resample`](https://github.com/donmccurdy/keyframe-resample-wasm) library may be
* provided. The WebAssembly version is usually much faster at processing large animation
* sequences, but may not be compatible with all runtimes and JavaScript build tools.
*
* Result: (0,0,0,0,1,1,1,0,0,0,0,0,0,0) → (0,0,1,1,0,0)
*
* Example:
*
* ```
* import { resample } from '@gltf-transform/functions';
* import { ready, resample as resampleWASM } from 'keyframe-resample';
*
* // JavaScript (slower)
* await document.transform(resample());
*
* // WebAssembly (faster)
* await document.transform(resample({ ready, resample: resampleWASM }));
* ```
*
* @privateRemarks Implementation based on THREE.KeyframeTrack#optimize().
* @category Transforms
*/
declare function resample(_options?: ResampleOptions): Transform;
//#endregion
//#region src/sequence.d.ts
interface SequenceOptions {
/** Frames per second, where one node is shown each frame. Default 10. */
fps?: number;
/** Pattern (regex) used to filter nodes for the sequence. Required. */
pattern: RegExp;
/** Name of the new animation. */
name?: string;
/** Whether to sort the nodes by name, or use original order. Default true. */
sort?: boolean;
}
/**
* Creates an {@link Animation} displaying each of the specified {@link Node}s sequentially.
*
* @category Transforms
*/
declare function sequence(_options?: SequenceOptions): Transform;
//#endregion
//#region src/simplify.d.ts
/** Options for the {@link simplify} function. */
interface SimplifyOptions {
/** MeshoptSimplifier instance. */
simplifier: unknown;
/** Target ratio (0–1) of vertices to keep. Default: 0.0 (0%). */
ratio?: number;
/** Limit on error, as a fraction of mesh radius. Default: 0.0001 (0.01%). */
error?: number;
/**
* Whether to lock topological borders of the mesh. May be necessary when
* adjacent 'chunks' of a large mesh (e.g. terrain) share a border, helping
* to ensure no seams appear.
*/
lockBorder?: boolean;
}
declare const SIMPLIFY_DEFAULTS: Required<Omit<SimplifyOptions, 'simplifier'>>;
/**
* Simplification algorithm, based on meshoptimizer, producing meshes with fewer
* triangles and vertices. Simplification is lossy, but the algorithm aims to
* preserve visual quality as much as possible for given parameters.
*
* The algorithm aims to reach the target 'ratio', while minimizing error. If
* error exceeds the specified 'error' threshold, the algorithm will quit
* before reaching the target ratio. Examples:
*
* - ratio=0.0, error=0.0001: Aims for maximum simplification, constrained to 0.01% error.
* - ratio=0.5, error=0.0001: Aims for 50% simplification, constrained to 0.01% error.
* - ratio=0.5, error=1: Aims for 50% simplification, unconstrained by error.
*
* Topology, particularly split vertices, will also limit the simplifier. For
* best results, apply a {@link weld} operation before simplification.
*
* Example:
*
* ```javascript
* import { simplify, weld } from '@gltf-transform/functions';
* import { MeshoptSimplifier } from 'meshoptimizer';
*
* await document.transform(
* weld({}),
* simplify({ simplifier: MeshoptSimplifier, ratio: 0.75, error: 0.001 })
* );
* ```
*
* References:
* - https://github.com/zeux/meshoptimizer/blob/master/js/README.md#simplifier
*
* @category Transforms
*/
declare function simplify(_options: SimplifyOptions): Transform;
/*