Skip to content

Skeleton & Skinning

Skins define how a mesh deforms based on a skeleton of joints. Skins are typically loaded from 3D files (glTF, FBX) — each joint is a node that can be manipulated.

Skins are attached to nodes:

local character = scene:find_node("Character")
local skin = character:get_skin()
skin:get_joint_count() -- number of joints
skin:get_joint_names() -- array of strings: { "Hips", "Spine", "LeftArm", ... }
-- Get a joint's node by index (0-based)
local joint = skin:get_joint_node(0)
-- Get a joint's node by name
local left_arm = skin:get_joint_node_by_name("LeftArm") -- Node or nil

Each joint is a regular Node, so you can read and write its transform properties.

Manipulate joint rotations for procedural animation:

local math3d = pl.math3d
-- Bend the left arm 45° around Z
local arm = skin:get_joint_node_by_name("LeftArm")
arm.rotation = math3d.quat_from_euler(0, 0, 45)
-- Nod the head
local head = skin:get_joint_node_by_name("Head")
head.rotation = math3d.quat_from_euler(15, 0, 0) -- pitch down 15°

Joint transforms are local (relative to the parent joint). The mesh deformation updates automatically when joint nodes change.

The inverse bind matrix for each joint transforms vertices from model space to the joint’s local space. These are read-only and set during import.

local ibm = skin:get_inverse_bind_matrix(0) -- mat4 (16 floats, column-major)
local skin = scene:find_node("Character"):get_skin()
local math3d = pl.math3d
local shoulder = skin:get_joint_node_by_name("RightShoulder")
local elbow = skin:get_joint_node_by_name("RightElbow")
local wrist = skin:get_joint_node_by_name("RightWrist")
-- Raise arm
shoulder.rotation = math3d.quat_from_euler(0, 0, -150)
elbow.rotation = math3d.quat_from_euler(0, 0, -30)
-- Animate wrist wave using timeline position
local t = pl.timeline.position
local wave_angle = math.sin(t * 6) * 20
wrist.rotation = math3d.quat_from_euler(0, wave_angle, 0)
  • Skins are loaded from files; creating skins from scratch in Lua is not currently supported.
  • For mesh skinning data (joint indices and weights per vertex), see Meshes.
  • For keyframe animation playback, see Animation.