| 1 | #!/usr/bin/env python3 |
| 2 | """Convert the CC0 test-body GLB into an FBX with Blender. |
| 3 | |
| 4 | The committed fixture tests/fixtures/bodies/test-body-male.fbx is the output |
| 5 | of this script. Re-run it when the generator changes: |
| 6 | |
| 7 | blender --background --python scripts/convert_test_body_to_fbx.py |
| 8 | |
| 9 | Blender is only a fixture tool. The application does not call Blender. |
| 10 | """ |
| 11 | |
| 12 | import sys |
| 13 | from pathlib import Path |
| 14 | |
| 15 | import bpy |
| 16 | |
| 17 | ROOT = Path(__file__).resolve().parents[1] |
| 18 | SOURCE = ROOT / "tests" / "fixtures" / "bodies" / "test-body-male.glb" |
| 19 | TARGET = ROOT / "tests" / "fixtures" / "bodies" / "test-body-male.fbx" |
| 20 | |
| 21 | |
| 22 | def main() -> None: |
| 23 | bpy.ops.wm.read_factory_settings(use_empty=True) |
| 24 | bpy.ops.import_scene.gltf(filepath=str(SOURCE)) |
| 25 | for obj in list(bpy.data.objects): |
| 26 | if not obj.name.startswith("test-body"): |
| 27 | bpy.data.objects.remove(obj, do_unlink=True) |
| 28 | actions = [action.name for action in bpy.data.actions] |
| 29 | armatures = [obj.name for obj in bpy.data.objects if obj.type == "ARMATURE"] |
| 30 | meshes = [obj.name for obj in bpy.data.objects if obj.type == "MESH"] |
| 31 | print("actions", actions) |
| 32 | print("armatures", armatures) |
| 33 | print("meshes", meshes) |
| 34 | bpy.ops.export_scene.fbx( |
| 35 | filepath=str(TARGET), |
| 36 | use_selection=False, |
| 37 | object_types={"ARMATURE", "MESH"}, |
| 38 | add_leaf_bones=False, |
| 39 | bake_anim=True, |
| 40 | bake_anim_use_all_actions=True, |
| 41 | bake_anim_use_nla_strips=True, |
| 42 | bake_anim_force_startend_keying=True, |
| 43 | path_mode="AUTO", |
| 44 | embed_textures=False, |
| 45 | axis_forward="-Z", |
| 46 | axis_up="Y", |
| 47 | apply_scale_options="FBX_SCALE_UNITS", |
| 48 | ) |
| 49 | print(f"wrote {TARGET} ({TARGET.stat().st_size} bytes)") |
| 50 | |
| 51 | |
| 52 | if __name__ == "__main__": |
| 53 | main() |