Role of the Bind Pose Matrix in glTF Skinning
In glTF (GL Transmission Format) 3D assets, the bind pose matrix—specifically implemented as the inverse bind matrix—serves as the foundational bridge between static mesh geometry and skeletal animation. This article explains the exact mathematical role of the inverse bind matrix during vertex skin transformation, how it counteracts joint rest positions to allow natural mesh deformation, and how glTF computes the final vertex positions in the skinning pipeline.
The Problem of Coordinate Spaces in Skeletal Animation
When a 3D model is created, its vertices are defined in a single local coordinate system (mesh or object space). However, a skeleton consists of a hierarchical chain of nodes (joints), each operating in its own local coordinate space.
If you apply a joint's current transformation directly to a vertex, the vertex will transform relative to the joint's current origin, ignoring where the joint was relative to the vertex when the mesh was initially bound. This produces severe mesh distortion and collapses the geometry toward the joint centers.
The Function of the Inverse Bind Matrix
To animate a vertex relative to a bone, the vertex must first be converted from mesh space into that specific bone's local space at its resting configuration (the bind pose).
The bind pose matrix represents the world/global transformation of a
joint when the mesh was originally attached to it. The
inverse of this matrix (inverseBindMatrix)
performs the reverse operation:
- Space Conversion: It transforms the vertex from the initial model coordinate space into the local coordinate frame of the target joint.
- Establishing an Offset: It calculates the spatial offset (distance and orientation) between the vertex and the joint in their default reference pose.
The glTF Skinning Equation
In the glTF specification, vertex skinning is implemented via Linear
Blend Skinning (LBS). Each skinned vertex contains attributes defining
which joints affect it (JOINTS_0) and the relative
influence of each joint (WEIGHTS_0).
For a given joint \(j\), the skinning transformation matrix \(S_j\) is calculated as:
\[S_j = GlobalTransform_j \times InverseBindMatrix_j\]
Where:
- \(InverseBindMatrix_j\) transforms the vertex from model space into the rest-pose local space of joint \(j\).
- \(GlobalTransform_j\) is the current runtime world transform of joint \(j\) (derived from the node hierarchy and active animations), which moves the vertex into its new animated position.
The final skinned vertex position \(v'\) is the weighted sum of these joint transformations applied to the original vertex \(v\):
\[v' = \sum_{i=0}^{n-1} (w_i \cdot S_{j_i} \cdot v)\]
Where \(w_i\) represents the weight and \(j_i\) represents the joint index for influence \(i\).
Implementation Details in glTF
- Data Storage: glTF stores these matrices via the
inverseBindMatricesproperty in theskinobject, referencing an accessor containing an array of 4x4 floating-point matrices (MAT4). - Default Values: If a glTF file omits the
inverseBindMatricesproperty, the specification mandates that an identity matrix is used for each joint, implying that the mesh vertices are already defined in the local spaces of their respective joints. - Pre-computation: Modern real-time rendering engines (such as WebGL or Vulkan pipelines) multiply the current joint transform by the inverse bind matrix once per joint per frame on the CPU or in a compute pass, passing the combined joint matrices to the vertex shader to minimize per-vertex calculations.