diff --git a/extensions/2.0/Khronos/KHR_character/README.md b/extensions/2.0/Khronos/KHR_character/README.md new file mode 100644 index 0000000000..ec4afe3591 --- /dev/null +++ b/extensions/2.0/Khronos/KHR_character/README.md @@ -0,0 +1,153 @@ +# KHR_character + +## Contributors + +- Ken Jakubzak, Meta +- Hideaki Eguchi / VirtualCast, Inc. +- K. S. Ernest (iFire) Lee, Independent Contributor / https://github.com/fire +- Shinnosuke Iwaki / VirtualCast, Inc. +- 0b5vr / pixiv Inc. +- Leonard Daly, Independent Contributor +- Nick Burkard, Meta +- Sarah Cooney, Microsoft XGTG +- Aaron Franke, Independent Contributor + +## Status + +**Draft** – This extension is not yet ratified by the Khronos Group and is subject to change. + +## Dependencies + +Written against the glTF 2.0 specification. + +Requires the extensions: `KHR_xmp_json_ld` + +This extension also leverages the `KHR_xmp_json_ld` pattern for attaching extensible metadata as JSON-LD blocks within glTF assets. For background on this approach, see: +[KHR_xmp_json_ld](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_xmp_json_ld) + +## Overview + +The `KHR_character` extension designates a glTF asset as representing an character. This top-level marker enables tools and runtimes to interpret the asset as containing character-specific content such as rigging, blendshapes, animation retargeting, or metadata. + +This extension does not define character features directly but acts as a root declaration that character-related extensions may be present, and that consumers should treat the asset using character-specific logic and pipelines. It's part of the wider set of KHR character extensions that are meant to be building blocks to represent a contract stating functionality and data requirements between a given model and an endpoint. + +The extension supports referencing the root `node` that represents the character and optionally includes structured metadata through the `KHR_xmp_json_ld` mechanism. + +## Extension Schema + +```json +{ + "extensions": { + "KHR_character": { + "rootNode": 0 + } + } +} +``` + +### Properties + +| Property | Type | Description | +| ---------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `rootNode` | integer | Index of the glTF `node` representing the root of the character hierarchy. This node should be a common ancestor of all nodes containing character-related data, such as meshes, skins, and animations. | + +## Metadata Attachment: KHR_xmp_json_ld + +character metadata should be expressed using the `KHR_xmp_json_ld` format, a structured mechanism for attaching JSON-LD metadata blocks to glTF files. In the context of `KHR_character`, this allows consistent expression of character provenance, licensing, creator, versioning, and intended use, among others. + +The `KHR_xmp_json_ld` block is placed at the root level of the glTF asset as part of the defined extension usage. Metadata keys and structures are defined in the shared Khronos character Metadata schema (TBD). + +| DC/XMP_JSON_LD Property | Why | Required | +| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -------- | +| dc:title | | Yes | +| dc:creator | | Yes | +| dc:license | | No | +| dc:rights | | No | +| dc:created | Date on which the asset was created | No | +| dc:publisher | Identifies the entity responsible for making the resource available; important for understanding the source and authority of the content. | No | +| dc:description | Context and a summary of the content | No | +| dc:subject | Can potentially be used for content tagging/association | No | +| dc:source | Important for tracing the provenance and ensuring proper attribution. | Yes | +| khr:version | | No | +| khr:thumbnailImage | | No | + +## Example + +```json +{ + "asset": { + "version": "2.0", + "extensions": { + "KHR_xmp_json_ld": { + "packet": 0 + } + } + }, + "scene": 0, + "scenes": [ + { + "nodes": [0] + } + ], + "nodes": [ + { + "name": "characterRoot" + } + ], + "extensionsUsed": ["KHR_character", "KHR_xmp_json_ld"], + "extensions": { + "KHR_character": { + "rootNode": 0 + }, + + "KHR_xmp_json_ld": { + "packets": [ + { + "@context": { + "dc": "http://purl.org/dc/elements/1.1/", + "vrm": "https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_vrm-1.0/meta.md" + }, + "dc:title": "Example Model", + "dc:creator": { + "@list": [ + "Author1", + "AuthorEmail1@email.com", + "Author2", + "AuthorEmail2@email.com" + ] + }, + "dc:license": { + "@list": [ + "https://vrm.dev/licenses/1.0/", + "https://example.com/third-party-license" + ] + }, + "dc:created": "2023-05-05", + "dc:rights": "Copyright information about the model", + "dc:publisher": "Imaginary Corporation A, LLC", + "dc:description": "A sentence, or paragraph describing the character at hand", + "dc:subject": { + "@list": ["Example trait", "Another example trait"] + }, + "dc:source": "imaginaryCompany.com/characterl", + "khr:version": "1.0", + "khr:thumbnailImage": 0 + } + ] + } + } +} +``` + +## Implementation Notes + +- `rootNode` is required, representing the index of the glTF `node` that serves as the root of the character hierarchy. This node should be a common ancestor of all nodes containing character-related data, such as meshes, skins, and animations. +- Consumers should use this marker as a signal to search for additional character-related extensions, including skeletal, expression, and other khronos character extensions. +- Support for `KHR_xmp_json_ld` is encouraged to ensure interoperable metadata across tools and runtimes. + +## Known Implementations + +## License + +This extension specification is licensed under the Khronos Group Extension License. +See: https://www.khronos.org/registry/gltf/license.html diff --git a/extensions/2.0/Khronos/KHR_character/schema/glTF.KHR_character.schema.json b/extensions/2.0/Khronos/KHR_character/schema/glTF.KHR_character.schema.json new file mode 100644 index 0000000000..a0225ccd1c --- /dev/null +++ b/extensions/2.0/Khronos/KHR_character/schema/glTF.KHR_character.schema.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "KHR_character glTF Document Extension", + "type": "object", + "description": "glTF extension for character-specific metadata and properties.", + "allOf": [ { "$ref": "glTFProperty.schema.json" } ], + "properties": { + "rootNode": { + "allOf": [{ "$ref": "glTFid.schema.json" }], + "description": "Index of the glTF node representing the root of the character hierarchy. This node should be a common ancestor of all nodes containing character-related data, such as meshes, skins, and animations." + }, + "extensions": { }, + "extras": { } + }, + "required": [ + "rootNode" + ] +} diff --git a/extensions/2.0/Khronos/KHR_character_expression/README.md b/extensions/2.0/Khronos/KHR_character_expression/README.md new file mode 100644 index 0000000000..35146ca267 --- /dev/null +++ b/extensions/2.0/Khronos/KHR_character_expression/README.md @@ -0,0 +1,144 @@ +# KHR_character_expression + +## Contributors + +- Ken Jakubzak, Meta +- Hideaki Eguchi / VirtualCast, Inc. +- K. S. Ernest (iFire) Lee, Independent Contributor / https://github.com/fire +- Shinnosuke Iwaki / VirtualCast, Inc. +- 0b5vr / pixiv Inc. +- Leonard Daly, Independent Contributor +- Nick Burkard, Meta +- Sarah Cooney, Microsoft XGTG +- Aaron Franke, Independent Contributor + +## Status + +**Draft** – This extension is not yet ratified by the Khronos Group and is subject to change. + +## Dependencies + +Written against the glTF 2.0 specification. +Requires the extension(s): `KHR_character` + +## Overview + +The `KHR_character_expression` extension provides a common interface for facial expression animations. It enables tools and runtimes to associate expressions like `blink`, `smile`, or `jawOpen` with specific animations in the glTF model's animations field. + +When used in conjunction with the other expression extensions, enables a data contract with endpoints allowing them to understand just what kind of data is present and being powered. + +This extension is purely descriptive: it does not define or store animation data itself. + +## Reference Expression Categories/Vocabularies + +Expressions in this context describe face-localized animations used to drive small and/or larger movements across the face and/or down-chain meshes needed for reasonable conveyance of emotion/intent. + +For examples of relevant types of expressions, you can reference concepts such as: + +- **Emotions** (Emotion-derived facial movements such as what [VRM defines as presets](https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_vrm-1.0/expressions.md), e.g. `happy`, `angry`, `surprised`) +- **Visemes** (A visual representations of mouth movements for parts of speech, e.g. `aa`, `oo`, `th`) +- **FACS** ([Facial Action Coding System (FACS)](https://en.wikipedia.org/wiki/Facial_Action_Coding_System) which is a system intended to describe visually distinguishable facial movements (and is often split further based on left/right), e.g. `brow lowerer`, `chin raiser`, `lid droop`) +- **Gestures and Actions** (Larger descriptors that describe general facial actionse (but not emotion), e.g. `blink`, `smile`, `jawOpen`) + +Optionally, these expressions may be aligned with industry standards (or an endpoint/experiences expected expressions set). + +## Extension Schema + +```json +{ + "extensions": { + "KHR_character_expression": { + "expressions": [ + { + "expression": "smile", + "animation": 0 + }, + { + "expression": "frown", + "animation": 1 + } + ] + } + } +} +``` + +### Properties + +| Property | Type | Description | +| ------------- | ------- | ------------------------------------------------------------------------------ | +| `expressions` | array | Array of mappings between animation/channels and expression labels. | +| `animation` | integer | Index into the glTF `animations[]` array representing an expression animation. | +| `expression` | string | Expression name this joint contributes to. | + +## Animation Integration + +- Expression timing, blending, and control must use glTF `animations` channels. +- This ensures consistency, ease of implementation, and interoperability across runtimes. + +Each animation channel used to drive an expression should operate within a **normalized 0-to-1 range**, where: + +- `0.0` indicates the expression is fully inactive. +- `1.0` indicates the expression is fully active. + +The transformation values themselves (e.g., degree of rotation or distance of translation) should scale proportionally with the normalized input range. + +This approach simplifies character implementation by centralizing expression playback in the glTF animation system and unifying runtime logic for blending and prioritization. + +### Recommended Interpolation for Binary Expressions + +For expressions that represent binary or toggle states (such as `blinkLeft`, `blinkRight`, or `jawOpen`), the use of glTF animation channels with `"interpolation": "STEP"` is strongly recommended. + +STEP interpolation ensures that an expression toggles cleanly between fully off (`0.0`) and fully on (`1.0`) states, providing crisp visual transitions and avoiding interpolation artifacts that could occur with `LINEAR` interpolation in binary scenarios. + +## Extension Example w/ typed extensions + +```json +{ + "extensions": { + "KHR_character_expression": { + "expressions": [ + { + "expression": "smile", + "animation": 0, + "extensions": { + "KHR_avatar_expression_joint": { + "channels": [0, 1] + }, + "KHR_avatar_expression_texture": { + "channels": [2] + }, + "KHR_avatar_expression_morphtarget": { + "channels": [4, 5] + } + } + }, + { + "expression": "frown", + "animation": 1, + "extensions": { + "KHR_avatar_expression_joint": { + "channels": [0] + }, + "KHR_avatar_expression_texture": { + "channels": [1, 2] + }, + "KHR_avatar_expression_morphtarget": { + "channels": [3] + } + } + } + ] + } + } +} +``` + +## Implementation Notes + +- Expression states should be normalized to the [0.0–1.0] range for consistent runtime interpretation. + +## License + +This extension is licensed under the Khronos Group Extension License. +See: https://www.khronos.org/registry/gltf/license.html diff --git a/extensions/2.0/Khronos/KHR_character_expression/schema/glTF.KHR_character_expression.schema.json b/extensions/2.0/Khronos/KHR_character_expression/schema/glTF.KHR_character_expression.schema.json new file mode 100644 index 0000000000..dc899a9cd9 --- /dev/null +++ b/extensions/2.0/Khronos/KHR_character_expression/schema/glTF.KHR_character_expression.schema.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "KHR_character_expression glTF Document Extension", + "type": "object", + "description": "glTF extension that provides a common interface for facial expression animations.", + "allOf": [ { "$ref": "glTFProperty.schema.json" } ], + "properties": { + "expressions": { + "type": "array", + "description": "Array of mappings between animation/channels and expression labels.", + "items": { + "type": "object", + "properties": { + "expression": { + "type": "string", + "description": "Expression name this animation contributes to." + }, + "animation": { + "allOf": [ + { + "$ref": "glTFid.schema.json" + } + ], + "description": "Index into the glTF animations array representing an expression animation." + }, + "extensions": { }, + "extras": { } + }, + "required": ["expression", "animation"], + "additionalProperties": false + }, + "minItems": 1 + }, + "extensions": { }, + "extras": { } + }, + "required": [ + "expressions" + ] +} diff --git a/extensions/2.0/Khronos/KHR_character_expression_joint/README.md b/extensions/2.0/Khronos/KHR_character_expression_joint/README.md new file mode 100644 index 0000000000..fdca73df4b --- /dev/null +++ b/extensions/2.0/Khronos/KHR_character_expression_joint/README.md @@ -0,0 +1,111 @@ +# KHR_character_expression_joint + +## Contributors + +- Ken Jakubzak, Meta +- Hideaki Eguchi / VirtualCast, Inc. +- K. S. Ernest (iFire) Lee, Independent Contributor / https://github.com/fire +- Shinnosuke Iwaki / VirtualCast, Inc. +- 0b5vr / pixiv Inc. +- Leonard Daly, Independent Contributor +- Nick Burkard, Meta +- Sarah Cooney, Microsoft XGTG +- Aaron Franke, Independent Contributor + +## Status + +**Draft** – This extension is not yet ratified by the Khronos Group and is subject to change. + +## Dependencies + +Written against the glTF 2.0 specification. +Requires the extension(s): `KHR_character`,`KHR_character_expression` +Typically used in conjunction with: `KHR_character_expression_mapping` + +## Overview + +The `KHR_character_expression_joint` extension provides a semantic mapping between facial expression names and joint-based animations. It enables tools and runtimes to associate expressions like `blink`, `smile`, or `jawOpen` with specific nodes whose transforms are animated using standard glTF animation channels. + +This extension is purely descriptive: it does not define or store animation data itself. + +## Reference Expression Categories/Vocabularies + +Expressions in this context describe face-localized animations used to drive small and/or larger movements across the face and/or down-chain meshes needed for reasonable conveyance of emotion/intent. + +For examples of relevant types of expressions, you can reference concepts such as: + +- **Emotions** (Emotion-derived facial movements such as what [VRM defines as presets](https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_vrm-1.0/expressions.md), e.g. `happy`, `angry`, `surprised`) +- **Visemes** (A visual representations of mouth movements for parts of speech, e.g. `aa`, `oo`, `th`) +- **FACS** ([Facial Action Coding System (FACS)](https://en.wikipedia.org/wiki/Facial_Action_Coding_System) which is a system intended to describe visually distinguishable facial movements (and is often split further based on left/right), e.g. `brow lowerer`, `chin raiser`, `lid droop`) +- **Gestures and Actions** (Larger descriptors that describe general facial actionse (but not emotion), e.g. `blink`, `smile`, `jawOpen`) + +Optionally, these expressions may be aligned with industry standards (or an endpoint/experiences expected expressions set). + +## Extension Schema + +```json +{ + "extensions": { + "KHR_character_expression": { + "expressions": [ + { + "expression": "smile", + "animation": 0, + "extensions": { + "KHR_character_expression_joint": { + "channels": [0, 1, 2] + } + } + }, + { + "expression": "frown", + "animation": 1, + "extensions": { + "KHR_character_expression_joint": { + "channels": [0, 1] + } + } + } + ] + } + } +} +``` + +### Properties + +| Property | Type | Description | +| ---------- | ----- | ---------------------------------------------------------------------------------------------------------------------------------- | +| `channels` | array | array representing channels that must correspond to either `"rotation"`, `"translation"`, or `"scale"`; indicates transform types. | + +## Animation Integration + +- Expression timing, blending, and control must use glTF `animations` channels. +- Animations targeting expression-driven `rotation`, `translation`, or `scale` must conform to glTF 2.0's animation model. +- This ensures consistency, ease of implementation, and interoperability across runtimes. + +Each animation channel used to drive an expression should operate within a **normalized 0-to-1 range**, where: + +- `0.0` indicates the expression is fully inactive. +- `1.0` indicates the expression is fully active. + +The transformation values themselves (e.g., degree of rotation or distance of translation) should scale proportionally with the normalized input range. + +This approach simplifies character implementation by centralizing expression playback in the glTF animation system and unifying runtime logic for blending and prioritization. + +### Recommended Interpolation for Binary Expressions + +For expressions that represent binary or toggle states (such as `blinkLeft`, `blinkRight`, or `jawOpen`), the use of glTF animation channels with `"interpolation": "STEP"` is strongly recommended. + +STEP interpolation ensures that an expression toggles cleanly between fully off (`0.0`) and fully on (`1.0`) states, providing crisp visual transitions and avoiding interpolation artifacts that could occur with `LINEAR` interpolation in binary scenarios. + +## Implementation Notes + +- Multiple joints may be assigned to the same expression. +- Expression states should be normalized to the [0.0–1.0] range for consistent runtime interpretation. +- This extension does not conflict with standard rigging or skinning systems. + +## License + +This extension is licensed under the Khronos Group Extension License. +See: https://www.khronos.org/registry/gltf/license.html diff --git a/extensions/2.0/Khronos/KHR_character_expression_joint/schema/KHR_character_expression.KHR_character_expression_joint.schema.json b/extensions/2.0/Khronos/KHR_character_expression_joint/schema/KHR_character_expression.KHR_character_expression_joint.schema.json new file mode 100644 index 0000000000..47b79e415b --- /dev/null +++ b/extensions/2.0/Khronos/KHR_character_expression_joint/schema/KHR_character_expression.KHR_character_expression_joint.schema.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "KHR_character_expression_joint KHR_character_expression Extension", + "type": "object", + "description": "glTF extension that extends KHR_character_expression to specify joint-based expression animations.", + "allOf": [ { "$ref": "glTFProperty.schema.json" } ], + "properties": { + "channels": { + "type": "array", + "description": "Array of animation channel indices that drive joint-based expressions.", + "items": { + "allOf": [ + { + "$ref": "glTFid.schema.json" + } + ], + "description": "Index of the animation channel in the referenced animation." + }, + "minItems": 1, + "uniqueItems": true + }, + "extensions": { }, + "extras": { } + }, + "required": [ + "channels" + ] +} diff --git a/extensions/2.0/Khronos/KHR_character_expression_mapping/README.md b/extensions/2.0/Khronos/KHR_character_expression_mapping/README.md new file mode 100644 index 0000000000..3376838e5a --- /dev/null +++ b/extensions/2.0/Khronos/KHR_character_expression_mapping/README.md @@ -0,0 +1,104 @@ +# KHR_character_expression_mapping + +## Contributors + +- Ken Jakubzak, Meta +- Hideaki Eguchi / VirtualCast, Inc. +- K. S. Ernest (iFire) Lee, Independent Contributor / https://github.com/fire +- Shinnosuke Iwaki / VirtualCast, Inc. +- 0b5vr / pixiv Inc. +- Leonard Daly, Independent Contributor +- Nick Burkard, Meta +- Sarah Cooney, Microsoft XGTG +- Aaron Franke, Independent Contributor + +## Status + +**Draft** – This extension is not yet ratified by the Khronos Group and is subject to change. + +## Dependencies + +Written against the glTF 2.0 specification. +Requires the extension(s): `KHR_character`,`KHR_character_expression` +Can be used alongside: `KHR_character_expression_morphtarget`, `KHR_character_expression_joints`, `KHR_character_expression_texture` or other expression sources + +## Overview + +This extension is intended to enable encoding multiple expression set mappings, mapping expression animations currently present in the model to expressions that a runtime/endpoint understands and can handle. + +## Reference Expression Categories/Vocabularies + +Expressions in this context describe face-localized animations used to drive small and/or larger movements across the face and/or down-chain meshes needed for reasonable conveyance of emotion/intent. + +For examples of relevant types of expressions, you can reference concepts such as: + +- **Emotions** (Emotion-derived facial movements such as what [VRM defines as presets](https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_vrm-1.0/expressions.md), e.g. `happy`, `angry`, `surprised`) +- **Visemes** (A visual representations of mouth movements for parts of speech, e.g. `aa`, `oo`, `th`) +- **FACS** ([Facial Action Coding System (FACS)](https://en.wikipedia.org/wiki/Facial_Action_Coding_System) which is a system intended to describe visually distinguishable facial movements (and is often split further based on left/right), e.g. `brow lowerer`, `chin raiser`, `lid droop`) +- **Gestures and Actions** (Larger descriptors that describe general facial actionse (but not emotion), e.g. `blink`, `smile`, `jawOpen`) + +Optionally, these expressions may be aligned with industry standards (or an endpoint/experiences expected expressions set). + +## Extension Schema/Example + +```json +{ + "extensionsUsed": ["KHR_character_expression_mapping"], + "extensions": { + "KHR_character_expression_mapping": { + "expressionSetMappings": { + "example_set_1": { + "Smile": [ + { "source": "smileLeft", "weight": 0.8 }, + { "source": "smileRight", "weight": 0.8 }, + ], + "LeftCheekRaise": [ + { "source": "smileLeft", "weight": 0.2 } + ], + "MouthOpen": [{ "source": "jawOpen", "weight": 1.0 }] + }, + "example_set_2": { + "smile_small": [ + { "source": "smileLeft", "weight": 0.2 } + { "source": "smileRight", "weight": 0.2 } + ], + "left_dimple": [ + { "source": "smileLeft", "weight": 0.8 } + ], + "mouth_open": [{ "source": "jawOpen", "weight": 1.0 }] + } + } + } + } +} +``` + +### Breakdown and Lower-Level Properties + +The structure of the data contained in the extension can be described as a dictionary of dictionaries: +Target Expression Set Name : Expression Mapping Dictionary (Expression Name : List/Array of objects containing the below properties) + +| Property | Type | Description | +| -------- | ------ | ------------------------------------------------------------- | +| `source` | string | Name of the source expression in the model. | +| `weight` | number | Relative influence of this source expression on the target. Weights represent the proportional contribution needed to achieve the desired target result and do not need to sum to any specific value. | + +### Mapping Types + +This extension supports both one-to-one and one-to-many mappings (as well as multiple instances of those mapping sets): + +- **One-to-one**: An expression maps directly to a single reference vocabulary term with a proportional weight. +- **One-to-many**: An expression is composed from multiple reference terms, blended using assigned weights. + +This allows developers to bridge between custom expression sets and shared vocabularies. + +## Implementation Notes + +- This extension is typically used at the top level of the glTF file. +- Expression names should match those used in `KHR_character_expression_morphtarget`, `KHR_character_expression_texture`, or `KHR_character_expression_joint`; +- Tools can interpret this mapping to apply automatic translation between expression sets. + +## License + +This extension specification is licensed under the Khronos Group Extension License. +See: https://www.khronos.org/registry/gltf/license.html diff --git a/extensions/2.0/Khronos/KHR_character_expression_mapping/schema/glTF.KHR_character_expression_mapping.schema.json b/extensions/2.0/Khronos/KHR_character_expression_mapping/schema/glTF.KHR_character_expression_mapping.schema.json new file mode 100644 index 0000000000..d582170255 --- /dev/null +++ b/extensions/2.0/Khronos/KHR_character_expression_mapping/schema/glTF.KHR_character_expression_mapping.schema.json @@ -0,0 +1,44 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "KHR_character_expression_mapping glTF Document Extension", + "type": "object", + "description": "glTF extension that enables encoding multiple expression set mappings, mapping source expressions present in the model to target expressions that a runtime/endpoint understands.", + "allOf": [ { "$ref": "glTFProperty.schema.json" } ], + "properties": { + "expressionSetMappings": { + "type": "object", + "description": "Dictionary of expression set mappings, where each key is a target expression set name.", + "additionalProperties": { + "type": "object", + "description": "Expression mapping dictionary where each key is a target expression name and each value is an array of source expression mappings.", + "additionalProperties": { + "type": "array", + "description": "Array of source expression mappings that contribute to the target expression.", + "items": { + "type": "object", + "properties": { + "source": { + "type": "string", + "description": "Name of the source expression in the model." + }, + "weight": { + "type": "number", + "description": "Relative influence of this source expression on the target. Weights represent the proportional contribution needed to achieve the desired target result." + } + }, + "required": [ + "source", + "weight" + ] + }, + "minItems": 1 + } + } + }, + "extensions": { }, + "extras": { } + }, + "required": [ + "expressionSetMappings" + ] +} diff --git a/extensions/2.0/Khronos/KHR_character_expression_morphtarget/README.md b/extensions/2.0/Khronos/KHR_character_expression_morphtarget/README.md new file mode 100644 index 0000000000..4012da98f0 --- /dev/null +++ b/extensions/2.0/Khronos/KHR_character_expression_morphtarget/README.md @@ -0,0 +1,346 @@ +# KHR_character_expression_morphtarget + +## Contributors + +- Ken Jakubzak, Meta +- Hideaki Eguchi / VirtualCast, Inc. +- K. S. Ernest (iFire) Lee, Independent Contributor / https://github.com/fire +- Shinnosuke Iwaki / VirtualCast, Inc. +- 0b5vr / pixiv Inc. +- Leonard Daly, Independent Contributor +- Nick Burkard, Meta +- Sarah Cooney, Microsoft XGTG +- Aaron Franke, Independent Contributor + +## Status + +**Draft** – This extension is not yet ratified by the Khronos Group and is subject to change. + +## Dependencies + +Written against the glTF 2.0 specification. +Requires the extension(s): `KHR_character`, `KHR_character_expression`, `KHR_animation_pointer` +Used in conjunction with: `KHR_character_expression_mapping` + +> **Note:** This extension explicitly requires `KHR_animation_pointer`. Implementations **MUST** support `KHR_animation_pointer` to use this extension. The `KHR_animation_pointer` extension enables animation of individual morph target weights via JSON pointers, which is essential for granular expression control. + +## Overview + +The `KHR_character_expression_morphtarget` extension provides semantic bindings between character expressions and specific morph target indices in a glTF mesh. These mappings enable higher-level expression control systems to reference the correct blendshapes when driving facial animation using glTF animation channels. + +This extension does **not** define animation data itself. Instead, it enables consistent reference of morph target indices across tools, runtimes, and expressions. + +## Reference Expression Categories/Vocabularies + +Expressions in this context describe face-localized animations used to drive small and/or larger movements across the face and/or down-chain meshes needed for reasonable conveyance of emotion/intent. + +For examples of relevant types of expressions, you can reference concepts such as: + +- **Emotions** (Emotion-derived facial movements such as what [VRM defines as presets](https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_vrm-1.0/expressions.md), e.g. `happy`, `angry`, `surprised`) +- **Visemes** (A visual representations of mouth movements for parts of speech, e.g. `aa`, `oo`, `th`) +- **FACS** ([Facial Action Coding System (FACS)](https://en.wikipedia.org/wiki/Facial_Action_Coding_System) which is a system intended to describe visually distinguishable facial movements (and is often split further based on left/right), e.g. `brow lowerer`, `chin raiser`, `lid droop`) +- **Gestures and Actions** (Larger descriptors that describe general facial actionse (but not emotion), e.g. `blink`, `smile`, `jawOpen`) + +Optionally, these expressions may be aligned with industry standards (or an endpoint/experiences expected expressions set). + +## Extension Schema + +```json +{ + "extensions": { + "KHR_character_expression": { + "expressions": [ + { + "expression": "smile", + "animation": 0, + "extensions": { + "KHR_character_expression_morphtarget": { + "channels": [0] + } + } + }, + { + "expression": "frown", + "animation": 1, + "extensions": { + "KHR_character_expression_morphtarget": { + "channels": [0] + } + } + } + ] + } + } +} +``` + +### Properties + +| Property | Type | Description | +| --------- | ------- | ------------------------------------------ | +| `channel` | integer | Index representing the `"weights"` channel | + +## Animation Integration (Expressions Tab Recommendation) + +This extension **does not animate morph targets directly**. It provides metadata only. + +All morph target expressions should be driven using standard glTF animation channels, targeting the `weights` path on the corresponding node: + +```json +{ + "animations": [ + { + "channels": [ + { + "sampler": 0, + "target": { + "node": 0, + "path": "weights" + } + } + ], + "samplers": [ + { + "input": 0, + "output": 1, + "interpolation": "LINEAR" + } + ] + } + ] +} +``` + +- Use `"interpolation": "STEP"` for binary/toggle expressions like `blink`. +- Each element of the `weights` array corresponds to one morph target on the associated mesh primitive. +- Expression systems should coordinate with these indices using the bindings declared by this extension. + +### Integration with KHR_animation_pointer + +For advanced animation control of morph target weights, implementations should use the [`KHR_animation_pointer`](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_animation_pointer) extension. This provides a standardized mechanism for animating weights via JSON pointers. + +As defined in the [glTF Object Model](https://github.com/KhronosGroup/glTF/blob/main/specification/2.0/ObjectModel.adoc#core-pointers), the following pointer templates are supported for morph target weights: + +| Pointer | Type | Description | +| ------- | ---- | ----------- | +| `/nodes/{}/weights` | `float[]` | Animate all morph target weights on a node simultaneously | +| `/nodes/{}/weights/{}` | `float` | Animate a specific morph target weight by index | + +Where `{}` is replaced with the corresponding array element index (e.g., `/nodes/0/weights` or `/nodes/0/weights/2`). + +### Example: Animating All Weights on a Node + +This example animates all morph target weights on a node using the `/nodes/i/weights` pointer: + +```json +{ + "animations": [ + { + "channels": [ + { + "sampler": 0, + "target": { + "path": "pointer", + "extensions": { + "KHR_animation_pointer": { + "pointer": "/nodes/0/weights" + } + } + } + } + ], + "samplers": [ + { + "input": 0, + "output": 1, + "interpolation": "LINEAR" + } + ] + } + ] +} +``` + +### Example: Animating a Specific Weight Index + +For more granular control, you can animate individual morph target weights using the `/nodes/i/weights/j` pointer. This is particularly useful when you want to animate a single expression without affecting other morph targets: + +```json +{ + "animations": [ + { + "channels": [ + { + "sampler": 0, + "target": { + "path": "pointer", + "extensions": { + "KHR_animation_pointer": { + "pointer": "/nodes/0/weights/2" + } + } + } + } + ], + "samplers": [ + { + "input": 0, + "output": 1, + "interpolation": "STEP" + } + ] + } + ] +} +``` + +In this example, only the morph target at index 2 (e.g., `blinkLeft`) is animated, while other weights remain unchanged. + +### Example: Animating Multiple Specific Weights + +To animate multiple specific morph targets independently (e.g., left and right blinks with different timing): + +```json +{ + "animations": [ + { + "name": "blink", + "channels": [ + { + "sampler": 0, + "target": { + "path": "pointer", + "extensions": { + "KHR_animation_pointer": { + "pointer": "/nodes/0/weights/2" + } + } + } + }, + { + "sampler": 1, + "target": { + "path": "pointer", + "extensions": { + "KHR_animation_pointer": { + "pointer": "/nodes/0/weights/3" + } + } + } + } + ], + "samplers": [ + { + "input": 0, + "output": 1, + "interpolation": "STEP" + }, + { + "input": 2, + "output": 3, + "interpolation": "STEP" + } + ] + } + ] +} +``` + +This allows `blinkLeft` (weight index 2) and `blinkRight` (weight index 3) to be animated with different timing samplers. + +This method ensures consistent and interoperable animation targeting for morph target-based expressions across glTF runtimes. + +## Example: Expression with glTF Animation + +### Step 1: Bind Expression to Morph Target + +```json +{ + "extensions": { + "KHR_character_expression": { + "expressions": [ + { + "expression": "smile", + "animation": 0, + "extensions": { + "KHR_character_expression_morphtarget": { + "channels": [0] + } + } + }, + { + "expression": "frown", + "animation": 1, + "extensions": { + "KHR_character_expression_morphtarget": { + "channels": [0] + } + } + } + ] + } + } +} +``` + +This binds morph target index 2 on mesh 0, primitive 0, to the expression `"blinkLeft"`. + +### Step 2: Animate the Morph Target via Node Weights + +```json +{ + "nodes": [ + { + "mesh": 0, + "weights": [0.0, 0.0, 0.0] + } + ], + "animations": [ + { + "channels": [ + { + "sampler": 0, + "target": { + "node": 0, + "path": "weights" + } + } + ], + "samplers": [ + { + "input": 0, + "output": 1, + "interpolation": "STEP" + } + ] + } + ] +} +``` + +The animation should update the relevant morph target weight (in this case index 2) between `0.0` and `1.0` to control the `"blinkLeft"` expression. The usage of `STEP` interpolation ensures clean toggles between on/off states. + +## Implementation Notes + +- This extension provides a consistent mapping between expression names and mesh targets, allowing glTF animation data to be expressive-aware. +- Multiple morph targets can be bound to the same expression. +- Tools may use this metadata to validate expression sets, retarget character blendshape names, or drive runtime animation. + +### Recommended Interpolation for Binary Expressions + +For expressions that represent binary or toggle states (such as eye blinks, mouth open/close states, or other on/off expressions), the use of glTF animation channels with `"interpolation": "STEP"` is strongly recommended. + +Using STEP interpolation ensures that the expression toggles cleanly between fully off (0) and fully on (1) states, providing crisp transitions and avoiding unintended interpolation artifacts. + +All expression-driven changes defined by this extension should rely on standard glTF animation mechanisms as described in the Khronos [Expressions Tab](https://docs.google.com/document/d/1ALRCPbXqQuWZvA9Sm2TsBFuW75h-of_lfD6sN7QwFU0/edit?pli=1&tab=t.x433oui5434f). + +- Expression timing, blending, and control must use glTF `animations` channels. +- Animations targeting expression-driven `weights` (for morphtargets) +- This ensures consistency, ease of implementation, and interoperability across runtimes. + +This approach simplifies character implementation by centralizing expression playback in the glTF animation system, reducing custom handling and improving cross-platform compatibility. + +## License + +This extension specification is licensed under the Khronos Group Extension License. +See: https://www.khronos.org/registry/gltf/license.html diff --git a/extensions/2.0/Khronos/KHR_character_expression_morphtarget/schema/KHR_character_expression.KHR_character_expression_morphtarget.schema.json b/extensions/2.0/Khronos/KHR_character_expression_morphtarget/schema/KHR_character_expression.KHR_character_expression_morphtarget.schema.json new file mode 100644 index 0000000000..91453ac1dd --- /dev/null +++ b/extensions/2.0/Khronos/KHR_character_expression_morphtarget/schema/KHR_character_expression.KHR_character_expression_morphtarget.schema.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "KHR_character_expression_morphtarget KHR_character_expression Extension", + "type": "object", + "description": "glTF extension that extends KHR_character_expression to specify morph target-based expression animations.", + "allOf": [ { "$ref": "glTFProperty.schema.json" } ], + "properties": { + "channels": { + "type": "array", + "description": "Array of animation channel indices that drive morph target-based expressions.", + "items": { + "allOf": [ + { + "$ref": "glTFid.schema.json" + } + ], + "description": "Index of the animation channel in the referenced animation." + }, + "minItems": 1, + "uniqueItems": true + }, + "extensions": { }, + "extras": { } + }, + "required": [ + "channels" + ] +} diff --git a/extensions/2.0/Khronos/KHR_character_expression_procedural/README.md b/extensions/2.0/Khronos/KHR_character_expression_procedural/README.md new file mode 100644 index 0000000000..5ecc2c3521 --- /dev/null +++ b/extensions/2.0/Khronos/KHR_character_expression_procedural/README.md @@ -0,0 +1,111 @@ +# KHR_character_expression_procedural + +## Contributors + +- Ken Jakubzak, Meta +- Hideaki Eguchi / VirtualCast, Inc. +- K. S. Ernest (iFire) Lee, Independent Contributor / https://github.com/fire +- Shinnosuke Iwaki / VirtualCast, Inc. +- 0b5vr / pixiv Inc. +- Leonard Daly, Independent Contributor +- Nick Burkard, Meta +- Sarah Cooney, Microsoft XGTG +- Aaron Franke, Independent Contributor + +## Status + +### TODO - Iterate on this to address some of the concerns around this current implementation, as well as incorporate it into the refactored extension hierarchy with KHR_character_expression + +**Draft** – This extension is not yet ratified by the Khronos Group and is subject to change. + +## Dependencies + +Written against the glTF 2.0 specification. +Requires the extension(s): `KHR_character`,`KHR_character_expression` +Works alongside: `KHR_character_expression_mapping`, `KHR_character_expression_joint`, `KHR_character_expression_texture`, `KHR_character_expression_morphtargets`. + +## Overview + +The `KHR_character_expression_procedural` extension introduces a metadata layer that defines which expressions are expected to be procedurally generated or controlled at runtime. This includes expressions such as: + +- **Timed blinking** +- **Eye darting** +- **Idle mouth movement** +- **Microexpressions** +- **Randomized twitches or gestures** + +Expressions in this context describe face-localized animations used to drive small and/or larger movements across the face and/or down-chain meshes needed for reasonable conveyance of emotion/intent. + +By labeling expressions as procedural, this extension enables runtime systems (e.g., animation controllers, live-tracking systems, or AI characters) to drive those expressions without conflict with animation data or user inputs. + +This metadata is **descriptive only**: it does not contain animation or behavior logic itself. Instead, it signals to tools and engines that the following expressions are _expected to be dynamically generated_. + +## Use Cases + +- Define which expressions are not statically animated but generated procedurally +- Avoid conflict between procedural and baked expression systems +- Inform rig exporters or runtime systems which expressions are reserved for real-time generation + +## Schema + +```json +{ + "extensions": { + "KHR_character_expression": { + "expressions": [ + { + "expression": "blink_left", + "animation": 0, + "extensions": { + "KHR_character_expression_procedural": { + "conflictResolution": "none" + } + } + }, + { + "expression": "mouth_purse", + "animation": 1, + "extensions": { + "KHR_character_expression_procedural": { + "conflictResolution": "blend" + } + } + } + ] + } + } +} +``` + +### Properties + +| Property | Type | Description | +| -------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `conflictResolution` | string | Conflict Resolution route used to determine the resolution strategy when multiple sources (procedural and non-procedural) want to control a given expression | + +## Expression Control Behavior + +To help define how procedural expressions interact with animation systems, this extension introduces an additional field called `conflictResolution`, inspired by the [VRM 1.0 specification](https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_vrm-1.0/expressions.md#lip-sync-procedural). + +Each procedural expression may declare a resolution strategy for combining procedural output with baked animation data. + +### `conflictResolution` Enum + +| Value | Meaning | +| ------- | ---------------------------------------------------------------------------------------- | +| `none` | No procedural influence. The expression is controlled exclusively by animation or input. | +| `block` | Procedural output _overrides_ animation data while active. | +| `blend` | Procedural and animation data may be blended or accumulated together. | + + +This allows developers to distinguish expressions meant to supplement animation (e.g., micro-blinks over emotive acting) versus those that must fully override input (e.g., forced gaze). + +## Implementation Notes + +- This extension is schema-only and does not contain behavior logic or animation data. +- Runtimes may use this to suppress baked animation for procedural targets. + +## License + +This extension is licensed under the Khronos Group Extension License. +See: https://www.khronos.org/registry/gltf/license.html diff --git a/extensions/2.0/Khronos/KHR_character_expression_procedural/schema/KHR_character_expression.KHR_character_expression_procedural.schema.json b/extensions/2.0/Khronos/KHR_character_expression_procedural/schema/KHR_character_expression.KHR_character_expression_procedural.schema.json new file mode 100644 index 0000000000..b89cbf7f1e --- /dev/null +++ b/extensions/2.0/Khronos/KHR_character_expression_procedural/schema/KHR_character_expression.KHR_character_expression_procedural.schema.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "KHR_character_expression_procedural KHR_character_expression Extension", + "type": "object", + "description": "glTF extension that extends KHR_character_expression to specify procedural expression animations.", + "allOf": [ { "$ref": "glTFProperty.schema.json" } ], + "properties": { + "conflictResolution": { + "type": "string", + "description": "Conflict resolution strategy used to determine how multiple sources (procedural and non-procedural) control a given expression.", + "enum": ["none", "block", "blend"], + "default": "none" + }, + "extensions": { }, + "extras": { } + } +} diff --git a/extensions/2.0/Khronos/KHR_character_expression_texture/README.md b/extensions/2.0/Khronos/KHR_character_expression_texture/README.md new file mode 100644 index 0000000000..446243dd12 --- /dev/null +++ b/extensions/2.0/Khronos/KHR_character_expression_texture/README.md @@ -0,0 +1,263 @@ +# KHR_character_expression_texture + +## Contributors + +- Ken Jakubzak, Meta +- Hideaki Eguchi / VirtualCast, Inc. +- K. S. Ernest (iFire) Lee, Independent Contributor / https://github.com/fire +- Shinnosuke Iwaki / VirtualCast, Inc. +- 0b5vr / pixiv Inc. +- Leonard Daly, Independent Contributor +- Nick Burkard, Meta +- Sarah Cooney, Microsoft XGTG +- Aaron Franke, Independent Contributor + +## Status + +**Draft** – This extension is not yet ratified by the Khronos Group and is subject to change. + +## Dependencies + +Written against the glTF 2.0 specification. +Requires the extension(s): `KHR_character`, `KHR_character_expression`, `KHR_animation_pointer` +Can be used alongside: `KHR_character_expression_mapping` + +## Overview + +The `KHR_character_expression_texture` extension enables expression-level control using texture swaps or UV transformations. This approach is beneficial for characters that represent expressions visually via changes in texture, such as cartoon or anime-style characters. + +- Expression timing, blending, and control must use glTF `animations` channels. +- Animations targeting expression-driven texture transforms must adhere strictly to glTF animation standards and khr_animation_pointer semantics. + +## Reference Expression Vocabulary + +Expressions in this context describe face-localized animations used to drive small and/or larger movements across the face and/or down-chain meshes needed for reasonable conveyance of emotion/intent. + +For examples of relevant types of expressions, you can reference concepts such as: + +- **Emotions** (Emotion-derived facial movements such as what [VRM defines as presets](https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_vrm-1.0/expressions.md), e.g. `happy`, `angry`, `surprised`) +- **Visemes** (A visual representations of mouth movements for parts of speech, e.g. `aa`, `oo`, `th`) +- **FACS** ([Facial Action Coding System (FACS)](https://en.wikipedia.org/wiki/Facial_Action_Coding_System) which is a system intended to describe visually distinguishable facial movements (and is often split further based on left/right), e.g. `brow lowerer`, `chin raiser`, `lid droop`) +- **Gestures and Actions** (Larger descriptors that describe general facial actionse (but not emotion), e.g. `blink`, `smile`, `jawOpen`) + +Optionally, these expressions may be aligned with industry standards (or an endpoint/experiences expected expressions set). + +## Extension Schema + +```json +{ + "extensions": { + "KHR_character_expression": { + "expressions": [ + { + "expression": "happy", + "animation": 0, + "extensions": { + "KHR_character_expression_texture": { + "channels": [0] + } + } + }, + { + "expression": "angry", + "animation": 1, + "extensions": { + "KHR_character_expression_texture": { + "channels": [0, 1] + } + } + } + ] + } + } +} +``` + +### Properties + +| Property | Type | Description | +| -------- | ---- | ----------- | + +| `channel` | array | Array representing the target channels that are texture transform-based | + +### textureTransform properties + +| Property | Type | Description | +| -------- | -------- | ------------------------------------ | +| `offset` | float[2] | UV offset for texture placement. | +| `scale` | float[2] | UV scale for texture transformation. | + +### Integration with KHR_animation_pointer + +For animations that involve texture swaps or UV transformations, implementations should rely on the [`KHR_animation_pointer`](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_animation_pointer) extension. This provides a standardized mechanism for animating texture and UV transform properties via JSON pointers. + +This method ensures consistent and interoperable animation targeting for texture-based expressions across glTF runtimes. + +## Clarifications on Texture Manipulations + +### Texture Swaps + +Dynamic texture swaps are not explicitly defined within the core glTF 2.0 specification. To implement runtime texture swapping: + +- Predefine all textures in the glTF `textures` array. +- Use the [`KHR_animation_pointer`](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_animation_pointer) extension to animate pointers that reference texture indices within material definitions. + +### UV Transformations + +UV manipulations (offset, scale, rotation) require the widely adopted [`KHR_texture_transform`](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_texture_transform) extension. + +- Animate properties within `KHR_texture_transform` using `KHR_animation_pointer`. +- Ensure these transforms are included explicitly in the glTF material definitions to enable animations. + +### Example Animation Setup using KHR_animation_pointer + +```json +{ + "animations": [ + { + "channels": [ + { + "sampler": 0, + "target": { + "extensions": { + "KHR_animation_pointer": { + "pointer": "/materials/2/pbrMetallicRoughness/baseColorTexture/index" + } + } + } + }, + { + "sampler": 1, + "target": { + "extensions": { + "KHR_animation_pointer": { + "pointer": "/materials/3/pbrMetallicRoughness/baseColorTexture/extensions/KHR_texture_transform/offset" + } + } + } + } + ], + "samplers": [ + { + "input": 0, + "output": 1, + "interpolation": "STEP" + }, + { + "input": 2, + "output": 3, + "interpolation": "LINEAR" + } + ] + } + ] +} +``` + +This clearly separates semantic bindings (the domain of this extension) from runtime animation states (handled by standard glTF animation mechanisms). + +### Recommended Interpolation for Binary Expressions + +For expressions that represent binary or toggle states (such as eye blinks, mouth open/close states, or other on/off expressions), the use of glTF animation channels with `"interpolation": "STEP"` is strongly recommended. + +Using STEP interpolation ensures that the expression toggles cleanly between fully off (0) and fully on (1) states, providing crisp transitions and avoiding unintended interpolation artifacts. + +## Example: Expression with glTF Animation + +### Step 1: Bind Expressions to Materials + +```json +{ + "extensions": { + "KHR_character_expression": { + "expressions": [ + { + "expression": "happy", + "animation": 0, + "extensions": { + "KHR_character_expression_texture": { + "channels": [0, 1] + } + } + }, + { + "expression": "angry", + "animation": 1, + "extensions": { + "KHR_character_expression_texture": { + "channels": [0, 1] + } + } + } + ] + } + } +} +``` + +This binds material index 2 to the `"happy"` expression and material index 3 to `"angry"`. + +### Step 2: Animate Texture Properties Using KHR_animation_pointer + +Animation of either the texture index or texture transform must be implemented using `KHR_animation_pointer`. + +```json +{ + "animations": [ + { + "channels": [ + { + "sampler": 0, + "target": { + "extensions": { + "KHR_animation_pointer": { + "pointer": "/materials/2/pbrMetallicRoughness/baseColorTexture/index" + } + } + } + }, + { + "sampler": 1, + "target": { + "extensions": { + "KHR_animation_pointer": { + "pointer": "/materials/3/pbrMetallicRoughness/baseColorTexture/extensions/KHR_texture_transform/offset" + } + } + } + } + ], + "samplers": [ + { + "input": 0, + "output": 1, + "interpolation": "STEP" + }, + { + "input": 2, + "output": 3, + "interpolation": "LINEAR" + } + ] + } + ] +} +``` + +## Implementation Notes + +- Use this extension when morph targets or joint animations alone are insufficient or stylistically undesirable for expressions. +- Expression-driven texture swaps or UV transformations are typically applied to materials on facial regions, such as eyes or mouth. +- This extension does not define animation sequences, only the semantic binding between expressions and textures or UV transforms. +- The `STEP` interpolation is ideal for switching texture indices (e.g., on/off or binary swaps). +- The `LINEAR` interpolation may be used for UV offset transitions or subtle animations. + +### Runtime Behavior + +- Expression weights should animate between `0.0` (off) and `1.0` (fully active). +- The character system uses these animations to blend or toggle texture visuals in accordance with semantic expressions. + +## License + +This extension specification is licensed under the Khronos Group Extension License. +See: https://www.khronos.org/registry/gltf/license.html diff --git a/extensions/2.0/Khronos/KHR_character_expression_texture/schema/KHR_character_expression.KHR_character_expression_texture.schema.json b/extensions/2.0/Khronos/KHR_character_expression_texture/schema/KHR_character_expression.KHR_character_expression_texture.schema.json new file mode 100644 index 0000000000..fd3a8c72c8 --- /dev/null +++ b/extensions/2.0/Khronos/KHR_character_expression_texture/schema/KHR_character_expression.KHR_character_expression_texture.schema.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "KHR_character_expression_texture KHR_character_expression Extension", + "type": "object", + "description": "glTF extension that extends KHR_character_expression to specify texture-based expression animations.", + "allOf": [ { "$ref": "glTFProperty.schema.json" } ], + "properties": { + "channels": { + "type": "array", + "description": "Array of animation channel indices that drive texture-based expressions.", + "items": { + "allOf": [ + { + "$ref": "glTFid.schema.json" + } + ], + "description": "Index of the animation channel in the referenced animation." + }, + "minItems": 1, + "uniqueItems": true + }, + "extensions": { }, + "extras": { } + }, + "required": [ + "channels" + ] +} diff --git a/extensions/2.0/Khronos/KHR_character_skeleton_bindpose/README.md b/extensions/2.0/Khronos/KHR_character_skeleton_bindpose/README.md new file mode 100644 index 0000000000..4b5a13fd56 --- /dev/null +++ b/extensions/2.0/Khronos/KHR_character_skeleton_bindpose/README.md @@ -0,0 +1,179 @@ +# KHR_character_skeleton_bindpose + +## Contributors + +- Ken Jakubzak, Meta +- Hideaki Eguchi / VirtualCast, Inc. +- K. S. Ernest (iFire) Lee, Independent Contributor / https://github.com/fire +- Shinnosuke Iwaki / VirtualCast, Inc. +- 0b5vr / pixiv Inc. +- Leonard Daly, Independent Contributor +- Nick Burkard, Meta +- Sarah Cooney, Microsoft XGTG +- Aaron Franke, Independent Contributor + +## Status + +**Draft** – This extension is not yet ratified by the Khronos Group and is subject to change. + +## Dependencies + +Written against the glTF 2.0 specification. +Requires the extension(s): `KHR_character` + +## Overview + +The `KHR_character_skeleton_bindpose` extension defines one or more canonical bind poses for the character's skeleton. These poses serve as neutral references that support animation retargeting, mesh deformation validation, and consistency across toolchains. Multiple bind poses can be defined per-skin (each with a unique pose type), using the same joint ordering as the skin's joints array for direct mapping and maximum simplicity. + +## Extension Schema + +This extension is applied to individual skins in the glTF file, providing bind pose data that corresponds directly to the skin's joint array. Multiple bind poses can be defined, each with a unique `poseType`. + +```json +{ + "skins": [ + { + "joints": [2, 5, 8, 12], + "extensions": { + "KHR_character_skeleton_bindpose": { + "poses": [ + { + "poseType": "TPose", + "bindPoses": [ + { "matrix": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] }, + { "matrix": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0.5, 0, 1] }, + { "matrix": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1.0, 0, 1] }, + { "matrix": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1.5, 0, 1] } + ] + }, + { + "poseType": "IPose", + "bindPoses": [ + { "matrix": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] }, + { "matrix": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0.5, 0, 1] }, + { "matrix": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1.0, 0, 1] }, + { "matrix": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1.5, 0, 1] } + ] + } + ] + } + } + } + ] +} +``` + +### Properties + +| Property | Type | Description | +| -------- | ---- | ----------- | +| `poses` | array | Array of pose definitions. Each pose has a unique `poseType` and corresponding `bindPoses` array. | + +#### poses Array + +Each entry in the `poses` array contains: + +| Property | Type | Description | +| -------- | ---- | ----------- | +| `poseType` | string | Enum: `TPose`, `APose`, `IPose`, `Custom`. Declares the pose classification for this bind pose set. | +| `bindPoses` | array | List of bind pose matrices corresponding directly to the skin's joints array. Each entry at index i corresponds to the joint at joints[i]. | + +#### bindPoses Array + +Each entry in the `bindPoses` array contains: + +| Property | Type | Description | +| -------- | ---- | ----------- | +| `matrix` | float[16] | Column-major 4x4 matrix defining the joint's bind pose in model space. | + +## Per-Skin Joint Indexing + +The `bindPoses` array uses per-skin joint indexing for maximum simplicity and glTF alignment: + +- **Direct Mapping**: Each entry in the bind pose array corresponds directly to the joint at the same index in the skin's joints array. +- **Simplicity**: No need for extra mapping or referencing—just match the order. +- **Consistency**: This matches how glTF handles skinning weights and inverse bind matrices, making it intuitive for tool and engine implementers. +- **Efficiency**: No redundant data; everything is scoped to the skin and its joints. + +### Example Mapping + +Given a skin with `"joints": [2, 5, 8, 12]`: + +- `bindPoses[0]` corresponds to joint node 2 +- `bindPoses[1]` corresponds to joint node 5 +- `bindPoses[2]` corresponds to joint node 8 +- `bindPoses[3]` corresponds to joint node 12 + +## Relationship to glTF 2.0 Skinning + +In glTF 2.0, `skins[].inverseBindMatrices` define the transformation from joint space to mesh space. However, those matrices may not capture the canonical rest pose or may be preprocessed for runtime purposes. + +This extension supplements or overrides that mechanism by defining joint rest positions explicitly in model space, allowing authoring tools and runtimes to perform consistent deformation or retargeting operations. + +> Note: This extension does not require that these bind pose matrices be used for skinning directly—they are semantic references to a "T-pose" or other neutral position. + +### poseType Enum + +| Value | Description | +| -------- | ------------------------------------------------------------------------------------ | +| `TPose` | Arms extended horizontally. Common neutral rest pose for retargeting. | +| `APose` | Arms angled downward (~45°). Used by some character authoring tools. | +| `IPose` | Arms resting at sides, parallel to the body. Natural standing pose. | +| `Custom` | Any pose that does not fit T-Pose, A-Pose, or I-Pose definitions. | + +## Implementation Notes + +- Each `poseType` value must be unique within the `poses` array. A skin cannot have two poses with the same `poseType`. +- The number of bind poses in each `bindPoses` array must match the number of joints in the skin's joints array. +- The bind pose matrix must be specified in model space (i.e., world-relative). +- This extension can be used in tandem with `skins[].inverseBindMatrices`, but is intended to expose clearer semantic meaning. +- Validation should ensure that each bindPoses array length equals joints array length. + +## Example + +```json +{ + "asset": { + "version": "2.0" + }, + "extensionsUsed": [ + "KHR_character", + "KHR_character_skeleton_biped", + "KHR_character_skeleton_bindpose" + ], + "skins": [ + { + "joints": [0, 1, 2, 3], + "extensions": { + "KHR_character_skeleton_bindpose": { + "poses": [ + { + "poseType": "TPose", + "bindPoses": [ + { "matrix": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] }, + { "matrix": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0.5, 0, 1] }, + { "matrix": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1.0, 0, 1] }, + { "matrix": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1.5, 0, 1] } + ] + }, + { + "poseType": "IPose", + "bindPoses": [ + { "matrix": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] }, + { "matrix": [0.707, 0, -0.707, 0, 0, 1, 0, 0, 0.707, 0, 0.707, 0, 0, 0.5, 0, 1] }, + { "matrix": [0.707, 0, -0.707, 0, 0, 1, 0, 0, 0.707, 0, 0.707, 0, 0, 1.0, 0, 1] }, + { "matrix": [0.707, 0, -0.707, 0, 0, 1, 0, 0, 0.707, 0, 0.707, 0, 0, 1.5, 0, 1] } + ] + } + ] + } + } + } + ] +} +``` + +## License + +This extension specification is licensed under the Khronos Group Extension License. +See: https://www.khronos.org/registry/gltf/license.html diff --git a/extensions/2.0/Khronos/KHR_character_skeleton_bindpose/schema/skin.KHR_character_skeleton_bindpose.schema.json b/extensions/2.0/Khronos/KHR_character_skeleton_bindpose/schema/skin.KHR_character_skeleton_bindpose.schema.json new file mode 100644 index 0000000000..dac61cf32a --- /dev/null +++ b/extensions/2.0/Khronos/KHR_character_skeleton_bindpose/schema/skin.KHR_character_skeleton_bindpose.schema.json @@ -0,0 +1,53 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "KHR_character_skeleton_bindpose glTF Skin Extension", + "type": "object", + "description": "glTF extension that defines one or more canonical bind poses for the character's skeleton applied to individual skins.", + "allOf": [ { "$ref": "glTFProperty.schema.json" } ], + "properties": { + "poses": { + "type": "array", + "description": "Array of pose definitions. Each pose has a unique poseType and corresponding bindPoses array.", + "items": { + "type": "object", + "properties": { + "poseType": { + "type": "string", + "description": "The type of pose this bind pose represents.", + "enum": ["TPose", "APose", "IPose", "Custom"], + "default": "TPose" + }, + "bindPoses": { + "type": "array", + "description": "Array of bind pose matrices corresponding directly to the skin's joints array. Each entry at index i corresponds to the joint at joints[i].", + "items": { + "type": "object", + "properties": { + "matrix": { + "type": "array", + "description": "Column-major 4x4 matrix defining the joint's bind pose in model space.", + "items": { + "type": "number" + }, + "minItems": 16, + "maxItems": 16 + } + }, + "required": ["matrix"], + "additionalProperties": false + }, + "minItems": 1 + } + }, + "required": ["poseType", "bindPoses"], + "additionalProperties": false + }, + "minItems": 1 + }, + "extensions": { }, + "extras": { } + }, + "required": [ + "poses" + ] +} diff --git a/extensions/2.0/Khronos/KHR_character_skeleton_mapping/README.md b/extensions/2.0/Khronos/KHR_character_skeleton_mapping/README.md new file mode 100644 index 0000000000..9807335922 --- /dev/null +++ b/extensions/2.0/Khronos/KHR_character_skeleton_mapping/README.md @@ -0,0 +1,119 @@ +# KHR_character_skeleton_mapping + +## Contributors + +- Ken Jakubzak, Meta +- Hideaki Eguchi / VirtualCast, Inc. +- K. S. Ernest (iFire) Lee, Independent Contributor / https://github.com/fire +- Shinnosuke Iwaki / VirtualCast, Inc. +- 0b5vr / pixiv Inc. +- Leonard Daly, Independent Contributor +- Nick Burkard, Meta +- Sarah Cooney, Microsoft XGTG +- Aaron Franke, Independent Contributor + +## Status + +**Draft** – This extension is not yet ratified by the Khronos Group and is subject to change. + +## Dependencies + +Written against the glTF 2.0 specification. +Requires the extension(s): `KHR_character` +Typically used in conjunction with: `KHR_character_skeleton_biped` + +## Overview + +The `KHR_character_skeleton_mapping` extension provides a mechanism to map a skeleton rig to a reference rig, enabling retargeting and compatibility across different skeleton topologies. This extension is particularly useful for normalizing diverse rig structures across platforms and authoring tools. It provides one-to-one mapping for maximum simplicity and compatibility. + +## Mapping to Known Standard Rigs + +In many real-world scenarios, developers must remap an character's native joint structure to a **known, standardized rig**—such as a runtime's internal character model or a predefined specification like VRM's Humanoid rig. + +This extension supports such cases by allowing one-to-one mappings between a model's joints and those of a **target standard rig**. + +These standard rigs are typically defined by the consuming platform, runtime, or service provider. Each standard rig: + +- Defines a fixed joint name vocabulary and hierarchy. +- Is assumed to be known at runtime and used for animation playback, retargeting, or IK purposes. + +### Extension Schema/Example: Mapping to VRM Humanoid + +The [VRM 1.0 Humanoid specification](https://github.com/vrm-c/vrm-specification/blob/master/specification/VRMC_vrm-1.0/humanoid.md) defines a standardized set of joints used across VRM-compatible platforms. + +Here's an example mapping from a custom rig into VRM Humanoid: + +```json +{ + "extensionsUsed": ["KHR_character_skeleton_mapping"], + "extensions": { + "KHR_character_skeleton_mapping": { + "skeletalRigMappings": { + "vrmHumanoid": { + "hips": "myRig_hips", + "head": "myRig_head", + "leftFoot": "myRig_leftFoot", + "rightFoot": "myRig_rightFoot", + "leftHand": "myRig_leftHand", + "rightHand": "myRig_rightHand" + }, + "example_rig": { + "hip_bone": "myRig_hips", + "head_bone": "myRig_head", + "l_foot_bone": "myRig_leftFoot", + "r_foot_bone": "myRig_rightFoot", + "l_hand_bone": "myRig_leftHand", + "r_hand_bone": "myRig_rightHand" + } + } + } + } +} +``` + +In this example: + +- The key is the target joint name defined by the target standard rig (e.g., `"hips"` for VRM Humanoid) +- The value is the source joint name from the model's native rig (e.g., `"myRig_hips"`) +- The system using this extension may understand what `"vrmHumanoid"` or `"example_rig"` means (i.e., the joint vocabulary and structure must be pre-declared by the consuming runtime) + +### Breakdown and Lower-Level Properties + +The structure of the data contained in the extension can be described as a dictionary of dictionaries: + +**Target Skeleton/Rig Name** : **Joint Mapping Dictionary** (Target Joint Name : Source Joint Name) + +Each mapping entry is simply: + +| Key (Target Joint) | Value (Source Joint) | Description | +| ------------------ | -------------------- | -------------------------------------------------------- | +| string | string | Direct mapping from target joint name in the target vocabulary to source joint name in the model's native rig | + +### Mapping Types + +This extension supports one-to-one mappings: + +- **One-to-one**: A target joint maps directly to a single source joint via a simple string value. + +This approach ensures maximum simplicity, compatibility across all engines and tools, and follows glTF's design philosophy of keeping core extensions simple and stable. + +## Mapping Registry and Target Namespaces + +While this extension does not mandate a central registry, developers are encouraged to: + +- Document the name and structure of their standard rigs +- Reuse identifiers like `"vrmHumanoid"`, `"unityHumanoid"`, or `"metaRig"` consistently +- Provide a public schema or joint list for validation and interoperability + +## Implementation Notes + +- Target joint names (keys) are defined by the target rig's vocabulary. +- Source joint names (values) are assumed to refer to nodes in the glTF `nodes` array. +- The reference rig vocabulary may be shared across engines or projects. +- This extension does not modify skinning behavior, but informs tooling and runtime animation retargeting. +- For validation, ensure that all source joint names (values) correspond to valid glTF nodes. + +## License + +This extension specification is licensed under the Khronos Group Extension License. +See: https://www.khronos.org/registry/gltf/license.html diff --git a/extensions/2.0/Khronos/KHR_character_skeleton_mapping/schema/glTF.KHR_character_skeleton_mapping.schema.json b/extensions/2.0/Khronos/KHR_character_skeleton_mapping/schema/glTF.KHR_character_skeleton_mapping.schema.json new file mode 100644 index 0000000000..a3c10c19f7 --- /dev/null +++ b/extensions/2.0/Khronos/KHR_character_skeleton_mapping/schema/glTF.KHR_character_skeleton_mapping.schema.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "KHR_character_skeleton_mapping glTF Document Extension", + "type": "object", + "description": "glTF extension that provides a mechanism to map a skeleton rig to a reference rig for retargeting and compatibility.", + "allOf": [ { "$ref": "glTFProperty.schema.json" } ], + "properties": { + "skeletalRigMappings": { + "type": "object", + "description": "Dictionary of target rig mappings. Each key is a target rig name, each value is a mapping dictionary.", + "additionalProperties": { + "type": "object", + "description": "Joint mapping dictionary. Each key is a target joint name in the target rig vocabulary, each value is the source joint name from the model's native rig.", + "additionalProperties": { + "type": "string", + "description": "Source joint name from the model's native rig." + } + } + }, + "extensions": { }, + "extras": { } + }, + "required": [ + "skeletalRigMappings" + ] +} diff --git a/extensions/2.0/Khronos/KHR_virtual_transform/README.md b/extensions/2.0/Khronos/KHR_virtual_transform/README.md new file mode 100644 index 0000000000..a246a4a3c4 --- /dev/null +++ b/extensions/2.0/Khronos/KHR_virtual_transform/README.md @@ -0,0 +1,224 @@ +# KHR_virtual_transform + +## Contributors + +- Ken Jakubzak, Meta +- Hideaki Eguchi / VirtualCast, Inc. +- K. S. Ernest (iFire) Lee, Independent Contributor / https://github.com/fire +- Shinnosuke Iwaki / VirtualCast, Inc. +- 0b5vr / pixiv Inc. +- Leonard Daly, Independent Contributor +- Nick Burkard, Meta +- Sarah Cooney, Microsoft XGTG +- Aaron Franke, Independent Contributor + +## Status + +**Draft** – This extension is not yet ratified by the Khronos Group and is subject to change. + +## Dependencies + +Written against the glTF 2.0 specification. + +## Overview + +The `KHR_virtual_transform` extension introduces _virtual transforms_; metadata-informed virtual 'nodes' that exist relative to a model's skeletal/node hierarchy, but are not nodes themselves and have settings whether to respect the parent node's position/rotation/scale at runtime. These virtual transforms serve as semantic attachment or control points for applications/systems to utilize; without it needing to be tied to a literal node hierarchy. + +In the context of characters, these virtual transforms serve as semantic attachment or control points for systems like look-at targeting, item equipping, IK hints, and seating positions. For other types of models, they can be leveraged for UI attach points, etc. + +Virtual transforms are defined via an offset transform relative to a single parent node, forming a tree structure that matches glTF's core specification. They do **not** participate in skinning and are evaluated at runtime for behavior logic and procedural animation. + +This extension is inspired in part by constructs like `lookAt` in VRM and aims to unify such functionality into a generic system usable across multiple glTF-based runtimes. + +## Use Cases + +- **Look-at targets** (for head/eye tracking) +- **Attachment points** (e.g., a weapon or tool socket) +- **Sitting or standing targets** +- **Camera or gaze anchors** +- **UI Attach points** - UI attachments that potentially need to maintain consistent size regardless of parent scaling +- **Reference markers** - Debug or measurement points that should be scale-independent + +## Schema + +```json +{ + "extensions": { + "KHR_virtual_transform": { + "virtualTransforms": [ + { + "name": "right_hand_attach", + "parent": 18, + "translation": [0.0, 0.1, 0.0], + "rotation": [0.0, 0.0, 0.0, 1.0], + "scale": [1.0, 1.0, 1.0], + "respectParentPosition": true, + "respectParentRotation": true, + "respectParentScale": true, + "tags": ["weapon_socket"] + }, + { + "name": "lookAt_target", + "parent": 8, + "translation": [0.0, 0.0, 0.35], + "rotation": [0.0, 0.0, 0.0, 1.0], + "scale": [1.0, 1.0, 1.0], + "respectParentPosition": true, + "respectParentRotation": true, + "respectParentScale": true, + "tags": ["look_at"] + }, + { + "name": "sitting_point", + "parent": 0, + "translation": [0.0, 0.0, -0.2], + "rotation": [0.0, 0.0, 0.0, 1.0], + "scale": [1.0, 1.0, 1.0], + "respectParentPosition": true, + "respectParentRotation": true, + "respectParentScale": true, + "tags": ["seating"] + }, + { + "name": "wrist_ui", + "parent": 19, + "translation": [0.0, 0.25, 0.0], + "rotation": [0.0, 0.0, 0.0, 1.0], + "scale": [1.0, 1.0, 1.0], + "respectParentPosition": true, + "respectParentRotation": false, + "respectParentScale": false, + "tags": ["ui"] + }, + { + "name": "debug_marker", + "parent": 5, + "translation": [0.0, 0.0, 0.0], + "rotation": [0.0, 0.0, 0.0, 1.0], + "scale": [0.1, 0.1, 0.1], + "respectParentPosition": true, + "respectParentRotation": false, + "respectParentScale": false, + "tags": ["debug", "marker"] + } + ] + } + } +} +``` + +### Properties + +| Property | Type | Description | +| ----------------------- | -------- | ------------------------------------------------------------------------------------------- | +| `name` | string | Semantic identifier of the virtual transform | +| `parent` | integer | Index of the parent node in the glTF `nodes[]` array | +| `translation` | float[3] | Local offset (X, Y, Z) relative to the parent node. Default: [0.0, 0.0, 0.0] | +| `rotation` | float[4] | Local orientation as quaternion (X, Y, Z, W) relative to the parent node. Default: [0.0, 0.0, 0.0, 1.0] | +| `scale` | float[3] | Local scale (X, Y, Z) relative to the parent node. Default: [1.0, 1.0, 1.0] | +| `respectParentPosition` | boolean | Whether this should respect the parent node position post-initialization. Default: true | +| `respectParentRotation` | boolean | Whether this should respect the parent node rotation post-initialization. Default: true | +| `respectParentScale` | boolean | Whether this should respect the parent node scale post-initialization. Default: true | +| `tags` | string[] | Array of strings used to denote tags that can be attributed to the virtual transform | + +## Hierarchy Structure + +Virtual transforms follow glTF's standard tree hierarchy model: + +- Each virtual transform has exactly one parent node (or none, if it's a root) +- This forms a **tree** structure (no cycles, no nodes with multiple parents) +- The world transform of a virtual transform is computed by recursively multiplying its local transform by its parent's world transform +- This matches the glTF core specification and how most 3D engines and DCC tools operate + +## Transform Calculation + +The world transform of a virtual transform is calculated as: + +1. Start with the virtual transform's local transform (translation, rotation, scale) +2. If `respectParentPosition` is true, apply the parent node's world position +3. If `respectParentRotation` is true, apply the parent node's world rotation +4. If `respectParentScale` is true, apply the parent node's world scale + +This provides complete control over which aspects of the parent's transform affect the virtual transform, enabling use cases such as UI elements that follow position but maintain independent size and orientation. + +## Examples + +### Right Hand Attachment Virtual Transform + +Example - Anchor for attaching objects, which want to respect all aspects of the parent joint transform + +- **Name**: `"right_hand_attach"` +- **Parent**: Right hand node (e.g., node index 18) +- **Translation**: `[0.0, 0.1, 0.0]` +- **Rotation**: `[0.0, 0.0, 0.0, 1.0]` +- **respectParentPosition**: `true` +- **respectParentRotation**: `true` +- **respectParentScale**: `true` +- **tags**: `["weapon_socket"]` + +### Look At Virtual Transform + +Example - Target for runtime look-at behavior (eyes/head alignment) + +- **Name**: `"lookAt_target"` +- **Parent**: Head joint (e.g., node index 8) +- **Translation**: `[0.0, 0.0, 0.35]` +- **Rotation**: `[0.0, 0.0, 0.0, 1.0]` +- **respectParentPosition**: `true` +- **respectParentRotation**: `true` +- **respectParentScale**: `true` +- **tags**: `["look_at"]` + +### Sitting Point Virtual Transform + +Example - Anchor point for aligning seated positions. + +- **Name**: `"sitting_point"` +- **Parent**: Pelvis joint (e.g., node index 0) +- **Translation**: `[0.0, 0.0, -0.2]` +- **Rotation**: `[0.0, 0.0, 0.0, 1.0]` +- **respectParentPosition**: `true` +- **respectParentRotation**: `true` +- **respectParentScale**: `true` +- **tags**: `["seating"]` + +### Wrist UI Virtual Transform + +Example - Anchor point for wrist UI, which follows position but maintains independent rotation and size. + +- **Name**: `"wrist_ui"` +- **Parent**: Wrist joint (e.g., node index 19) +- **Translation**: `[0.0, 0.25, 0.0]` +- **Rotation**: `[0.0, 0.0, 0.0, 1.0]` +- **respectParentPosition**: `true` +- **respectParentRotation**: `false` +- **respectParentScale**: `false` +- **tags**: `["ui"]` + +### Debug Marker Virtual Transform + +Example - A debug marker that follows the parent's position but maintains independent orientation and consistent size. + +- **Name**: `"debug_marker"` +- **Parent**: Spine joint (e.g., node index 5) +- **Translation**: `[0.0, 0.0, 0.0]` +- **Rotation**: `[0.0, 0.0, 0.0, 1.0]` +- **Scale**: `[0.1, 0.1, 0.1]` (small marker) +- **respectParentPosition**: `true` +- **respectParentRotation**: `false` +- **respectParentScale**: `false` (maintains consistent size) +- **tags**: `["debug", "marker"]` + +## Implementation Notes + +- Virtual transforms should exist only within this extension and **must not overlap with joints used in skinning**. +- Their transformation is computed at runtime by applying the offset to the parent node's world transform. +- Tools and runtimes may expose these as attachable sockets or semantic retargeting anchors. +- The single-parent hierarchy ensures compatibility with all glTF-compliant tools and engines. +- For advanced constraint-based relationships (multiple influences), consider using a dedicated constraint system rather than multiple parents in the scene graph. +- The three `respectParent*` flags provide fine-grained control over transform inheritance, enabling use cases from fully-inherited transforms to completely independent positioning. + +## License + +This extension is licensed under the Khronos Group Extension License. +See: https://www.khronos.org/registry/gltf/license.html diff --git a/extensions/2.0/Khronos/KHR_virtual_transform/schema/glTF.KHR_virtual_transform.schema.json b/extensions/2.0/Khronos/KHR_virtual_transform/schema/glTF.KHR_virtual_transform.schema.json new file mode 100644 index 0000000000..5c6878db7b --- /dev/null +++ b/extensions/2.0/Khronos/KHR_virtual_transform/schema/glTF.KHR_virtual_transform.schema.json @@ -0,0 +1,90 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "KHR_virtual_transform glTF Document Extension", + "type": "object", + "description": "glTF extension that introduces virtual transforms - semantic attachment or control points relative to the model's node hierarchy.", + "allOf": [ { "$ref": "glTFProperty.schema.json" } ], + "properties": { + "virtualTransforms": { + "type": "array", + "description": "Array of virtual transform objects.", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Semantic identifier of the virtual transform." + }, + "parent": { + "allOf": [ + { + "$ref": "glTFid.schema.json" + } + ], + "description": "Index of the parent node in the glTF nodes array." + }, + "translation": { + "type": "array", + "description": "Local offset (X, Y, Z) relative to the parent node.", + "items": { + "type": "number" + }, + "minItems": 3, + "maxItems": 3, + "default": [0.0, 0.0, 0.0] + }, + "rotation": { + "type": "array", + "description": "Local orientation as quaternion (X, Y, Z, W) relative to the parent node.", + "items": { + "type": "number" + }, + "minItems": 4, + "maxItems": 4, + "default": [0.0, 0.0, 0.0, 1.0] + }, + "scale": { + "type": "array", + "description": "Local scale (X, Y, Z) relative to the parent node.", + "items": { + "type": "number" + }, + "minItems": 3, + "maxItems": 3, + "default": [1.0, 1.0, 1.0] + }, + "respectParentPosition": { + "type": "boolean", + "description": "Whether this should respect the parent node position post-initialization.", + "default": true + }, + "respectParentRotation": { + "type": "boolean", + "description": "Whether this should respect the parent node rotation post-initialization.", + "default": true + }, + "respectParentScale": { + "type": "boolean", + "description": "Whether this should respect the parent node scale post-initialization.", + "default": true + }, + "tags": { + "type": "array", + "description": "Array of strings used to denote tags that can be attributed to the virtual transform.", + "items": { + "type": "string" + } + } + }, + "required": ["name", "parent"], + "additionalProperties": false + }, + "minItems": 1 + }, + "extensions": { }, + "extras": { } + }, + "required": [ + "virtualTransforms" + ] +}