Skip to content

KHR_skeleton_bone - #2626

Open
aaronfranke wants to merge 1 commit into
KhronosGroup:mainfrom
aaronfranke:KHR_skeleton_bone
Open

aaronfranke wants to merge 1 commit into
KhronosGroup:mainfrom
aaronfranke:KHR_skeleton_bone

Conversation

@aaronfranke

@aaronfranke aaronfranke commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

This pull request proposes a new extension, KHR_skeleton_bone. This extension serves to solve multiple problems at once with skeleton bones. Broadly, two categories:

  1. It allows for the definition of bone length and connectivity.

    • These properties are primarily useful for DCC interchange, allowing this information to not be lost when it is desired to be preserved.
    • These properties secondarily useful for some niche runtime use cases that benefit from them. For example, bone length is useful for spring bones.
    • Bone length has been traditionally encoded in the form of "_end" nodes (see "Add Leaf Bones" in Blender's glTF exporter and FBX exporter), but this is a lossy workaround to the lack of a real data field.
  2. It provides a stronger definition of bones and skeletons.

    • Bones are explicitly defined, can be defined even without a corresponding skin joint, required to be dedicated to the skeleton hierarchy, and required to be contiguous up to the skeleton.
    • Skeletons are explicitly defined, recommended to be unique to a skin, required to not have partial overlaps, and required for each skin to explicitly refer to its skeleton root node.
    • Skinned meshes are explicitly required to be direct children of the skeleton root node that their skin refers to.
    • The widely-adopted convention of bone length along the node's local +Y axis is now defined explicitly.
    • If another glTF extension wants to only apply to bones, it can extend KHR_skeleton_bone instead of node to structurally restrict its scope, depending on KHR_skeleton_bone's requirements rather than its own prose.

Both of these categories are important common needs that have been requested by many parties over the years, but have not been pushed to the finish line. This extension is a proposal to finally address the needs of skeleton bone style skinning in glTF in a comprehensive and strict way.

This extension is intended to be always optional. Applications that do not care about bone length, bone connectivity, or the stricter hierarchy can ignore this extension entirely, loading it as a normal glTF file with skinned meshes and joint hierarchies. Applications that do care about having strict skeletons and bones can export with this extension to indicate their compliance and semantic meaning. Asset authors that do not wish to be restricted to these requirements can choose to not use this extension. These restrictions are not desired by some parts of the glTF ecosystem, and therefore this should be an optional extension, not required, nor part of the core glTF specification.

I am proposing that these properties and requirements be defined in the same extension because the strict requirements for bones depend on the ability to clearly define bones, and the requirements of applications that need clearly defined bones are usually these requirements. For example, if we want to declare that the bone hierarchy is contiguous, what happens if a glTF node that isn't used as a joint is in the middle of the bone hierarchy? We could require that the node be used as a joint, but that would be strange if the node has no skinning influence over any mesh. KHR_skeleton_bone provides an alternative way to explicitly mark that node as a bone. Assets specifying KHR_skeleton_bone on each bone node would also make the requirements easier to validate just by looking at the nodes array. It is also reasonable to propose these as two separate extensions if the community feels that is more appropriate, but then each would need to indicate their interaction with the other. I think it is better to have them together in one extension.

@aaronfranke

Copy link
Copy Markdown
Contributor Author

The list of requirements in KHR_skeleton_bone grew a bit larger after I reviewed the previous proposals and issues, especially the extensive discussion in issue #1665. Specifically, here are some summaries, and how KHR_skeleton_bone, partially or fully, addresses and/or supersedes them.


KHR_skin_strict: #1747

KHR_skin_strict introduces no new features, but rather acts as a profile for restricting glTF skins. It is essentially half of KHR_skeleton_bone.

KHR_skeleton_bone declares "All bones form a contiguous hierarchy descendant from the skeleton root node, meaning that each and every bone MUST have a contiguous chain of bone parenting leading up to a skeleton root node; the parent node of a bone MUST either be another bone or the skeleton root node itself". This supersedes this text in KHR_skin_strict: "All joints in a skin must define a single fully-connected subtree, sharing a single root joint, with no non-joint nodes coming between the joints of the tree", except that KHR_skeleton_bone defines this based on bones, which are not necessarily joints.

KHR_skin_strict requires that the skeleton root itself is also a joint, while KHR_skeleton_bone does not require this, only that a contiguous hierarchy of bones exists up to the skeleton, not including the skeleton itself. I do not think this restriction has value, and at least for my use cases, the skeleton root should not be a joint itself (should we explicitly forbid this?). For characters, the root bone is usually "Hips", which is a child of the skeleton root.

KHR_skeleton_bone declares "All bone nodes MUST NOT have a mesh, camera, or light attached to the same node, and SHOULD NOT have similar extension-defined 'non-bone components' attached to the same node, such that the glTF node serves only as a bone, and any non-bone components are be attached to child glTF nodes". This supersedes this text in KHR_skin_strict: "A joint node must not define any other functional role, such as node.mesh, node.camera, or node.skin. Likewise, joint nodes cannot use extensions that instantiate resources in the scene (like KHR_lights_punctual)". These are essentially identical in their functionality. The node.skin property does not need to be explicitly forbidden, because it is dependentRequired on the node.mesh property, which is already forbidden.

KHR_skeleton_bone declares "All bones belong to a single skeleton, which SHOULD correspond to one glTF skin, but MAY correspond to multiple glTF skins". This supersedes this text in KHR_skin_strict: "A joint node must belong only to a single skin". The KHR_skeleton_bone version is a bit more permissive, and the reason this is different is to accommodate the most common complaint brought up by commenters (see #1665), while still enforcing the most critical aspect desired by skeleton engines (single skeleton), while further recommending (SHOULD) that a single skin is used, which would match KHR_skin_strict. I would also be happy to change this to match KHR_skin_strict, but I think this version is a reasonable compromise and is more likely to be accepted by the glTF community.

KHR_skeleton_bone declares "The "skeleton" property of all glTF skins is required when KHR_skeleton_bone is used in the file". This supersedes this text in KHR_skin_strict: "All skins must define the skeleton property".


STAIK_skeletons: #1695

STAIK_skeletons requires that the skeleton root itself is also a joint, while KHR_skeleton_bone does not require that the skeleton root itself is a joint. I do not think this restriction has value, and at least for my use cases, the skeleton root should not be a joint itself.

KHR_skeleton_bone declares "The "skeleton" property of all glTF skins is required when KHR_skeleton_bone is used in the file". This supersedes this text in STAIK_skeletons: "The skeleton optional property is now required".

STAIK_skeletons adds a lot of JSON structure. By comparison, KHR_skeleton_bone is much simpler, leveraging existing glTF structure, similarly to KHR_skin_strict.


"Stricter Skin Definitions": #1669

KHR_skeleton_bone declares "All bones form a contiguous hierarchy descendant from the skeleton root node". This supersedes this text in the PR: "All joints defined in a skin must form a connected subtree".

KHR_skeleton_bone declares "All bones belong to a single skeleton". This supersedes this text in the PR: "A node may only be defined as a joint by a single skin". The KHR_skeleton_bone version is a bit more permissive, see the justification for this in the KHR_skin_strict section above.

KHR_skeleton_bone allows defining bones explicitly, but still keeps the implicit definition of bones through glTF skin joints. This provides an alternative to the text "Implementation Note: A node definition does not specify whether the node should be treated as a joint. Client implementations may wish to traverse the skins array first, marking each joint node" with the caveat that this note still mostly applies, only with "does not specify" changed to "does not necessarily specify", because now there is a way for nodes to specify that they are bones. The core glTF 2.0 specification already states this: "A node object does not specify whether it is a joint. Client implementations may need to traverse the skins array first, marking each joint node", but I'm mentioning it here because this text was touched by that PR.

KHR_skeleton_bone makes the "skeleton" property of all glTF skins required, while the PR removes that property entirely. It replaces it with "skin parent", but this is under-defined.


"Sharing skeletons between two skinned mesh": #1285

Brief discussion here, but the main point discussed there is that stricter skeleton definitions are needed but should be done by an extension. KHR_skeleton_bone is that extension.


"Stricter Skinning Requirements": #1665

KHR_skeleton_bone declares "All bones form a contiguous hierarchy descendant from the skeleton root node", which covers the point of "All joints in a skin must form a connected subtree with the skeleton root/direct parent".

KHR_skeleton_bone declares "The "skeleton" property of all glTF skins is required when KHR_skeleton_bone is used in the file", which covers the point of "The skeleton root should be defined".


"Stricter Skinning Requirements" comment from @reduz: #1665 (comment)

KHR_skeleton_bone declares "The "skeleton" property of all glTF skins is required", which covers the point of "Making the skeleton property in skin mandatory".

KHR_skeleton_bone declares "All bones form a contiguous hierarchy descendant from the skeleton root node", which covers the points of "All joints in a skin must be connected" and "should always be to the parent of a bone".

KHR_skeleton_bone declares "All bones MUST belong to a single skeleton", which covers the point of "Having multiple skins share joints should be outright forbidden", except that it is more permissive, allowing multiple skins so long as the skeleton root is the same.

The point of "A mesh must only be able to bind to a single skin" is not relevant, since glTF nodes can only have one skin property.


"Stricter Skinning Requirements" comment from @marstaik: #1665 (comment)

Marstaik's entire comment is worth a read, but his conclusion is this:

I believe that glTF needs to treat joints as first class citizens. They need to be marked on the nodes, the same way that meshes and skins are marked, even if its just a boolean flag.

KHR_skeleton_bone directly enables this, by allowing the KHR_skeleton_bone extension to be added to nodes to explicitly mark them as bones in the skeleton hierarchy, even when the bone is not used as a glTF skin joint.

KHR_skeleton_bone declares "All bone nodes MUST NOT have a mesh, camera, or light attached to the same node, and SHOULD NOT have similar extension-defined "non-bone components" attached to the same node", which covers the point of "Joints must not be a mesh, camera, or anything other than a transform" in the comment.


For any of these, please let me know if you would like me to tweak the wording of KHR_skeleton_bone to better address the issues. I made this text very verbose to be explicit, but maybe this is too verbose and could be simplified.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant