Every single time. I finish a rig, animate the whole thing with IK legs and arms, then open Unity and stare at a skeleton that just sits in T-pose because I forgot to bake before export. Again. So I finally wrote a script to handle it. It detects IK-constrained bones, walks the full chain, selects them, bakes visual transforms to keyframes, and strips the constraints.
import bpy
def get_ik_bone_names(armature_obj):
ik_bones = set()
for bone in armature_obj.pose.bones:
for constraint in bone.constraints:
if constraint.type == 'IK':
chain_len = constraint.chain_count
b = bone
for _ in range(chain_len if chain_len > 0 else 10):
ik_bones.add(b.name)
if b.parent is None:
break
b = b.parent
return list(ik_bones)
def bake_ik_to_fk(obj, frame_start=None, frame_end=None):
if obj is None or obj.type != 'ARMATURE':
print("Select an armature first.")
return
scene = bpy.context.scene
fs = frame_start if frame_start is not None else scene.frame_start
fe = frame_end if frame_end is not None else scene.frame_end
bpy.context.view_layer.objects.active = obj
bpy.ops.object.mode_set(mode='POSE')
ik_bone_names = get_ik_bone_names(obj)
if not ik_bone_names:
print(f"No IK constraints found on {obj.name}, nothing to bake.")
bpy.ops.object.mode_set(mode='OBJECT')
return
bpy.ops.pose.select_all(action='DESELECT')
for name in ik_bone_names:
if name in obj.pose.bones:
obj.pose.bones[name].bone.select = True
bpy.ops.nla.bake(
frame_start=fs,
frame_end=fe,
only_selected=True,
visual_keying=True,
clear_constraints=True,
use_current_action=True,
bake_types={'POSE'}
)
bpy.ops.object.mode_set(mode='OBJECT')
print(f"Baked {len(ik_bone_names)} bones: {ik_bone_names}")
bake_ik_to_fk(bpy.context.active_object)
The key flag is visual_keying=True. Without it you get the pre-constraint values, which is completely useless. clear_constraints=True strips the IK solver afterward so you're not exporting dead constraint data that some importers complain about.
A few things I ran into:
constraint.pole_target and add that bone separately. Haven't had drift issues without it but it probably matters on some rigs.That NLA case is what I'd love help with. My current thought is muting all NLA tracks, soloing each strip in turn, baking, then restoring state, but it feels brittle. Anyone doing this more cleanly? Also curious whether people just rely on the FBX exporter's built-in bake_anim=True option instead of pre-baking in Blender. I've had it miss tail bones on longer chains and stopped trusting it.