wrote a Blender script to normalize hip height across mocap takes, tired of every clip starting at a different elevation

361 views 0 replies

The problem I kept running into: shoot 6 takes in the same session with the same actor and somehow every clip has the hip bone sitting at a slightly different world-space height. Actor stands a little differently at calibration, the suit vest shifts, capture software picks a slightly different reference pose. Small variance, but in-engine when you transition between clips the root lurches up or down at the cut.

Wrote a script that goes through every action in the .blend, finds the Z location FCurve for the root/hip bone, samples it at a reference frame, and shifts every keyframe uniformly by the delta to a target baseline. Not stretching the animation, just translating the whole Z curve up or down.

import bpy

HIP_BONE = 'mixamorig:Hips'  # update to match your rig
TARGET_HEIGHT = 1.0           # world-space Z at rest, in meters
REF_FRAME = 1                 # frame to sample for baseline height

def normalize_hip_heights():
    armature = bpy.context.object
    if not armature or armature.type != 'ARMATURE':
        print('Select an armature first.')
        return

    for action in bpy.data.actions:
        bone_path = 'pose.bones["{}"].location'.format(HIP_BONE)
        z_curve = next(
            (fc for fc in action.fcurves
             if fc.data_path == bone_path and fc.array_index == 2),
            None
        )
        if z_curve is None:
            continue

        ref_z = z_curve.evaluate(REF_FRAME)
        delta = TARGET_HEIGHT - ref_z

        if abs(delta) < 0.005:
            print('[skip] {}: already near target ({:.4f}m)'.format(action.name, ref_z))
            continue

        for kp in z_curve.keyframe_points:
            kp.co[1] += delta
            kp.handle_left[1] += delta
            kp.handle_right[1] += delta

        z_curve.update()
        print('[ok] {}: shifted {:+.4f}m'.format(action.name, delta))

normalize_hip_heights()

Assumptions baked in:

  • Root motion rig: the hip/root bone has actual world-space Z location keyframes. In-place rigs won't benefit from this.
  • Z-up coordinate system (standard Blender import from most suit software)
  • Frame 1 is a clean standing pose, not mid-action
  • Update HIP_BONE to match your naming: Hips, Root, mixamorig:Hips, etc.

What it doesn't fix: variance in hip height throughout the take from actor posture drift or floor contact differences. This is purely a per-action origin offset correction, the relative motion inside each clip stays untouched.

One thing I'm unsure about: whether sampling a median over the first 10–15 frames would be more robust than a single reference frame. Some takes have a small settle at frame 1 before the actor finds their natural stance, which skews the baseline. Anyone tackled this and found a better sampling approach?

Moonjump
Forum Search Shader Sandbox
Sign In Register