Parenting Non-Skinned Meshes to glTF Bones
This article explains how to attach rigid, non-skinned geometry directly to skeletal bones within a glTF asset. By utilizing glTF's native scene graph hierarchy, developers can parent standard static meshes—such as weapons, armor pieces, or props—directly to animated bone nodes. This approach eliminates the performance overhead of linear blend skinning, removes the need for vertex weights or inverse bind matrices, and ensures that the attached mesh seamlessly follows skeletal animations across standard runtime engines.
Understanding glTF Nodes and Bones
In the glTF 2.0 specification, a bone is simply an ordinary
node in the document's nodes array. While a
skin object aggregates these nodes into an indexed
joints list for vertex-weighted deformation, the bones
themselves remain standard scene graph entities with standard transform
properties (translation, rotation,
scale, or matrix). Because every bone is a
node, any bone can act as a parent to other nodes in the glTF
hierarchy.
The Direct Parenting Mechanism
To attach a non-skinned mesh to a bone, link the mesh node as a child
of the target bone node without assigning a skin property
to the mesh's node.
The structure requires two key configurations:
- Target Bone Node: The node acting as the skeleton
joint must include the attachment node's index in its
childrenarray. - Attachment Mesh Node: A node referencing the
meshindex is positioned as a child of the bone. This node defines the local offset (position, rotation, scale) relative to the bone's coordinate space. It must not contain askinindex.
glTF JSON Structure Example
The following excerpt demonstrates a hand bone node
(Node 1) parenting a static sword mesh
(Node 2):
{
"nodes": [
{
"name": "Armature_Root",
"children": [1]
},
{
"name": "Bone_Hand_R",
"translation": [0.0, 1.2, 0.0],
"rotation": [0.0, 0.0, 0.0, 1.0],
"children": [2]
},
{
"name": "Prop_Sword",
"mesh": 0,
"translation": [0.0, 0.1, 0.05],
"rotation": [0.7071, 0.0, 0.0, 0.7071]
}
],
"meshes": [
{
"name": "SwordMesh",
"primitives": [
{
"attributes": {
"POSITION": 0,
"NORMAL": 1
},
"indices": 2
}
]
}
]
}In this setup:
Bone_Hand_Rmay be referenced in askin.jointsarray for deforming a character's body mesh.Prop_Swordis a child ofBone_Hand_R.- The
SwordMeshprimitive only contains basic attributes likePOSITIONandNORMAL. It does not containJOINTS_0orWEIGHTS_0attributes.
Implementation Considerations
- Local Coordinate Offsets: The
translation,rotation, andscaleon the child mesh node act as socket offsets. Modifying these values repositions the object relative to the bone's origin and orientation. - Transform Inheritance: When skeletal animations
update the transforms of
Bone_Hand_R, standard scene graph matrix multiplication causes the child node to follow identically in runtime engines such as Three.js, Babylon.js, and Godot. - Exporting from DCC Tools: In digital content
creation software like Blender, this is achieved by selecting the prop
object, selecting the armature, switching to Pose Mode, selecting the
specific target bone, and pressing
Ctrl + Pto choose Bone parenting. When exporting to glTF 2.0, the exporter translates this relationship into standard nested glTF nodes.