How glTF Skin References the Skeletal Hierarchy
In glTF (GL Transmission Format), skeletal animation relies on the
skin object to bridge renderable mesh geometry with
hierarchical transformation trees. Rather than introducing a specialized
data type for bones, glTF repurposes standard scene graph nodes to act
as joints. The skin property references these nodes through
indexed arrays, maps initial rest poses using inverse bind matrices, and
establishes the relationship between vertex weighting data and dynamic
skeletal transforms.
Joints as Standard Nodes
In glTF, joints do not exist as distinct structural entities; they
are ordinary elements in the top-level nodes array. The
hierarchical relationship—where parent bones control child bones—is
created strictly using the children arrays of those nodes.
A joint's position, rotation, and scale in the scene graph define its
local transform relative to its parent joint.
The skin.joints Array
The core mechanism linking a skeleton to a skin is the
joints array within the skin object. This
array contains integer indices that point directly to entries in the
root-level nodes array:
{
"skins": [
{
"name": "ArmatureSkin",
"inverseBindMatrices": 0,
"joints": [10, 11, 12, 13]
}
]
}In this example, nodes 10, 11, 12, and 13 function as joints for this
specific skin. The position of a node index within the
joints array dictates its local "joint index" (e.g., node
10 is joint 0, node 11 is joint 1).
This local joint index is critical because mesh vertex attributes
(JOINTS_0, JOINTS_1) do not reference global
node indices; instead, they reference the index within this
skin.joints list.
The
inverseBindMatrices Property
To correctly deform a mesh, the engine must know the mesh's position
relative to each joint in the neutral "bind pose." The
skin.inverseBindMatrices property points to an accessor
containing an array of 4x4 floating-point matrices.
- There is a strict 1:1 mapping: the number of matrices matches the
length of the
jointsarray. - Matrix
itransforms vertex coordinates from the mesh's local space into the local coordinate space of jointiat the time of binding. - During runtime animation, each vertex is transformed by its inverse bind matrix, followed by the joint node's current global transform, scaled by the vertex weight.
The skeleton Property
The skin object includes an optional
skeleton property, which contains a single integer
referencing the root node of the joint hierarchy:
{
"skins": [
{
"skeleton": 9,
"joints": [10, 11, 12, 13]
}
]
}The node specified by skeleton is often the direct
parent of the root joint (or the root joint itself). While not required
for mathematically calculating the joint transforms, it serves as a hint
to runtime engines about where the skeletal hierarchy starts, optimizing
scene graph traversals and bounding box calculations.
Connecting the Mesh to the Skin
A visual node connects geometry to the skeletal system by defining
both a mesh index and a skin index
simultaneously:
{
"nodes": [
{
"name": "SkinnedCharacter",
"mesh": 0,
"skin": 0
}
]
}When this node is evaluated, the renderer takes the geometry from
mesh: 0, reads the skinning attributes
(JOINTS_0 and WEIGHTS_0) from each vertex
primitive, and evaluates them against the runtime transforms of the
nodes declared in skin: 0.