The setup: character rig with ~35 animations in the NLA editor, engine team needs individual FBX files per animation. Every session I was doing the same manual dance: solo the strip, adjust the frame range, export FBX, unsolo, repeat. Took maybe 10–15 minutes per pass and I was exporting multiple times a day during polish.
Wrote a script that handles the whole thing:
import bpy
import os
def export_nla_strips_as_fbx(output_dir, objects=None):
if objects is None:
objects = [o for o in bpy.context.selected_objects if o.type == 'ARMATURE']
os.makedirs(output_dir, exist_ok=True)
scene = bpy.context.scene
for arm in objects:
if not arm.animation_data or not arm.animation_data.nla_tracks:
continue
tracks = arm.animation_data.nla_tracks
for track in tracks:
for strip in track.strips:
# Mute everything, unmute just this track
for t in tracks:
t.mute = True
track.mute = False
scene.frame_start = int(strip.frame_start)
scene.frame_end = int(strip.frame_end)
filepath = os.path.join(output_dir, strip.name + '.fbx')
bpy.ops.export_scene.fbx(
filepath=filepath,
use_selection=True,
object_types={'ARMATURE', 'MESH'},
bake_anim=True,
bake_anim_use_all_actions=False,
bake_anim_use_nla_strips=True,
bake_anim_step=1.0,
bake_anim_simplify_factor=0.0,
add_leaf_bones=False,
)
print('Exported: ' + filepath)
# Restore: unmute all tracks when done
for t in tracks:
t.mute = False
export_nla_strips_as_fbx('/path/to/output/')
A few caveats:
- Exit tweakmode before running. Behavior gets weird if a strip is being edited when this fires.
- Doesn't handle stacked strips on the same track (rare, but it happens), so those'll export together
bake_anim_simplify_factor=0.0 is intentional. I'd rather ship full curves and let the engine's import settings handle compression.
Saves me a lot of time. The part I'm least happy with is the track muting approach. It feels fragile, and writing to scene.frame_start/frame_end as a side effect is annoying if you're running this mid-session. Anyone found a cleaner way to isolate individual NLA strips for export without touching global scene state?