Hazel

IK, Constraints & Spring Bones

Procedural animation on top of your clips, provided by the renzora_ik plugin. You add components to bones (or to the character) in the Inspector, under the Animation page, and every frame they adjust the pose the animation player just wrote, before it reaches the skin, attached props and physics:

ComponentPut it onWhat it does
TwoBoneIkthe end bone (hand, foot)Reaches an arm or leg for a target, bending the elbow/knee toward a pole
LookAta head, eye, or turret boneAims one of the bone's axes at a target, within a cone
FootIkthe character's model rootPlants both feet on uneven ground, lowers the hips, tilts the feet onto slopes
RotationLimitany boneClamps swing (a cone) and twist (a range) after animation and IK
CopyRotation / CopyPositionany entityFollows another entity's world rotation or position, per axis
SpringBonesthe first bone of a chainSimulates the chain as damped springs: hair, tails, ears, antennae
SpringColliderany bone or entityA sphere spring chains of the same character cannot pass through

Constraints run in a fixed order each frame: copy constraints, foot IK, two-bone IK, look-at, rotation limits, spring bones. So limits clamp what the IK asked for, and spring chains hang off the finished pose.

Only in a running game. Like animation, cloth and physics, constraints run in Play mode and in a shipped game, not while editing: what you place in the editor is what the scene file says. Leaving Play puts every bone the animation does not drive back where it was.

Every component has a Weight from 0 (the animation untouched) to 1 (fully applied). 0 switches a constraint off without removing it, and a script can ramp it (see Scripting).

Targets are names

Targets, poles, sources and foot bones are given by entity name, not picked: a name survives saving, reloading and re-importing the model. When several entities share a name (two copies of one character both have a Head), the lookup prefers the one under the same top-level parent as the constraint, so each character finds its own LookTarget. Foot and hip bones are only ever looked up inside the character that owns the FootIk.

An empty target name uses the component's Target Position (world space) instead, which is what scripts usually set.

Two-bone IK

Add TwoBoneIk to the hand or foot. Its parent is taken as the elbow/knee and its grandparent as the shoulder/thigh, the way glTF skeletons are laid out. A target out of reach is reached for as far as the limb goes.

FieldDefaultEffect
TargetemptyName of the entity to reach for
Target Position0, 0, 0World position used when Target is empty
Pole TargetemptyName of an entity the elbow/knee points toward
Pole Direction0, 0, 0Direction the elbow/knee points, in the space of the shoulder/thigh's parent, so it turns with the character. Zero keeps the bend plane the animation has
Weight1Animation (0) to fully solved (1)
Keep End RotationonThe hand/foot keeps its animated world rotation while the limb bends
Match Target RotationoffThe hand/foot takes the target entity's rotation instead (gripping a handle)

If your rig has twist bones between the elbow and the wrist, the "parent is the mid joint" rule picks the twist bone; put the IK on a bone whose parent and grandparent are the real joints.

Look-at / aim

FieldDefaultEffect
Target / Target Positionempty / originWhat to look at
Aim Axis0, 0, 1The bone-local axis that points at the target
Up Axis0, 1, 0The bone-local axis kept toward World Up
World Up0, 0, 0Zero keeps the animated roll (right for heads). Set 0, 1, 0 to keep a turret level
Max Angle70Furthest the aim turns away from where the animation points it, degrees. A target outside the cone is followed to its edge
Weight1

The limit is measured from the animated direction, so a clip that already turns the head keeps its turn and the look-at adds at most Max Angle to it. For a natural head turn, put a LookAt on the neck at a low weight and another on the head.

Foot IK

Put FootIk on the character's model root: the entity at its feet, whose height the walk cycle treats as the floor. Each frame a ray is cast down under each animated ankle, through the physics query API, so it works with whichever physics engine the project uses. The character's own colliders (its ragdoll bodies, a controller capsule on a parent) are ignored. With no physics engine installed, the ground is a flat plane at Fallback Ground Height.

How far the ground under each foot sits above or below the character's floor is added to that ankle, so a lifted foot mid-stride stays lifted over the step it is crossing. The hips drop by the lower foot's amount (never rise), and each leg is solved with two-bone IK to reach.

FieldDefaultEffect
Left Foot / Right FootLeftFoot / RightFootAnkle bone names. Each one's parent is the knee and grandparent the thigh. Leave one empty for a single foot
HipsHipsThe pelvis bone lowered to keep both feet reachable
Ray Height0.5How far above the ankle the ray starts: the tallest step a foot can find
Ray Depth0.6How far below the ankle it reaches
Fallback Ground Height0Ground height with no physics engine
Max Hip Drop0.4Furthest the hips go down, metres
Align To GroundonTilt each foot onto the slope it stands on
Max Slope40Steepest slope a foot tilts onto, degrees
Smoothing15How quickly feet and hips follow the ground, per second. Lower is smoother on bumpy ground
Weight1Set it to 0 while the character is airborne

Rotation limits

RotationLimit clamps a bone's local rotation, measured from the rotation the bone had when the component was added (for a model straight out of its glTF, its rest pose):

FieldDefaultEffect
Twist Axis0, 1, 0The bone's own axis, local. glTF bones point down +Y
Swing Limit60Widest the bone may swing off its rest direction, degrees
Twist Min / Twist Max-30 / 30Twist range about the bone's axis, degrees
Weight1

Swing and twist are clamped separately, so an over-twisted forearm keeps pointing where it pointed and only its roll is corrected.

Copy constraints

CopyRotation and CopyPosition make an entity follow another one's world rotation or position. X/Y/Z pick which world axes are copied (Euler angles for rotation; with all three on the whole rotation is copied). Offset is added after copying (degrees for rotation, metres for position).

Spring bones

Add SpringBones to the first bone of a chain. That bone, its first child, that child's first child and so on down to a leaf are simulated as damped springs pulled back toward the animated pose, so moving the character, or the clip, makes the chain lag, swing and settle. The last bone of the chain is its tip and only follows; if the final segment should swing too, give it an end bone (most exporters already do). A bone with several chains hanging off it, like a head of hair strands, needs one SpringBones on each strand.

FieldDefaultEffect
Stiffness150Pull back toward the animated shape. Higher is stiffer
Damping8Damping of wobble relative to the animation. Higher settles faster
Drag0.5Air drag on all motion, per second
Gravity0, -3, 0Acceleration on every joint, world space. A steady wind works too
Radius0.02Joint radius against Spring Colliders
Teleport Distance1A jump of the chain's root further than this in one frame (a respawn) snaps the chain to the pose instead of whipping it
Weight10 switches the simulation off; turning it back on starts from rest

The simulation runs at a fixed 120 steps per second whatever the frame rate, so hair behaves the same at 30 fps and 144 fps. Only the bones' rotations are changed: a chain bends and swings but never stretches.

SpringCollider (Radius, Offset in the entity's local space) keeps spring chains of the same character (the same top-level parent) out of a sphere: put one on the head under the hair, on the hips under a tail.

Scripting

Every function takes a bone name first, looked up under the script's own entity, so a script on the character reaches its own bones and never another character's bone of the same name. An empty name ("") means every constraint of that kind on the entity and below it.

FunctionEffect
ik_set_target(bone, x, y, z)Reach a TwoBoneIk for a world position (clears its Target name)
ik_set_target_entity(bone, name)Reach for the entity with this name
ik_set_pole(bone, x, y, z)Set the Pole Direction (clears its Pole Target)
ik_set_weight(bone, weight)Blend a TwoBoneIk, 0..1
look_at_set_target(bone, x, y, z)Aim a LookAt at a world position
look_at_set_target_entity(bone, name)Aim at the entity with this name
look_at_set_weight(bone, weight)Blend a LookAt, 0..1
foot_ik_set_weight(weight)Blend the FootIk on this entity (or below it)
copy_constraint_set_weight(bone, weight)Blend a CopyRotation/CopyPosition
rotation_limit_set_weight(bone, weight)Blend a RotationLimit
spring_bones_set_weight(bone, weight)Blend a spring chain; 0 switches it off
spring_bones_reset(bone)Snap a spring chain to the animated pose, at rest
-- character.lua
function on_ready()
    -- Grip the door handle with the right hand, watch the player.
    ik_set_target_entity("RightHand", "DoorHandle")
    look_at_set_target_entity("Head", "Player")
end

function on_jump()
    foot_ik_set_weight(0.0) -- feet free in the air
end

function on_land()
    foot_ik_set_weight(1.0)
end

Read any field back through reflection as usual: get("TwoBoneIk.weight").

Related