Last active
October 3, 2025 22:01
-
-
Save avramovic/2c50405b32dece773882693b0d251ad1 to your computer and use it in GitHub Desktop.
Revisions
-
avramovic revised this gist
Oct 3, 2025 . 1 changed file with 59 additions and 95 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,5 +1,8 @@ import bpy import sys import os # Parse arguments argv = sys.argv argv = argv[argv.index("--") + 1:] src_file = os.path.abspath(argv[0]) @@ -18,131 +21,93 @@ bpy.ops.import_scene.gltf(filepath=src_file) # Find source armature arm_source = next((obj for obj in bpy.context.scene.objects if obj.type == "ARMATURE"), None) if not arm_source: raise Exception("No armature found in source file") print("Source armature:", arm_source.name) # Import target print("Importing target...") bpy.ops.import_scene.gltf(filepath=tgt_file) # Find target armature arm_target = next((obj for obj in bpy.context.scene.objects if obj.type == "ARMATURE" and obj != arm_source), None) if not arm_target: raise Exception("No armature found in target file") print("Target armature:", arm_target.name) # Bone mapping bone_map = { "DEF-hips": "Hips", "DEF-spine.001": "Spine", "DEF-spine.002": "Spine1", "DEF-spine.003": "Spine2", "DEF-neck": "Neck", "DEF-head": "Head", "DEF-shoulder.L": "LeftShoulder", "DEF-upper_arm.L": "LeftArm", "DEF-forearm.L": "LeftForeArm", "DEF-hand.L": "LeftHand", "DEF-thumb.01.L": "LeftHandThumb1", "DEF-thumb.02.L": "LeftHandThumb2", "DEF-thumb.03.L": "LeftHandThumb3", "DEF-f_index.01.L": "LeftHandIndex1", "DEF-f_index.02.L": "LeftHandIndex2", "DEF-f_index.03.L": "LeftHandIndex3", "DEF-f_middle.01.L": "LeftHandMiddle1", "DEF-f_middle.02.L": "LeftHandMiddle2", "DEF-f_middle.03.L": "LeftHandMiddle3", "DEF-f_ring.01.L": "LeftHandRing1", "DEF-f_ring.02.L": "LeftHandRing2", "DEF-f_ring.03.L": "LeftHandRing3", "DEF-f_pinky.01.L": "LeftHandPinky1", "DEF-f_pinky.02.L": "LeftHandPinky2", "DEF-f_pinky.03.L": "LeftHandPinky3", "DEF-shoulder.R": "RightShoulder", "DEF-upper_arm.R": "RightArm", "DEF-forearm.R": "RightForeArm", "DEF-hand.R": "RightHand", "DEF-thumb.01.R": "RightHandThumb1", "DEF-thumb.02.R": "RightHandThumb2", "DEF-thumb.03.R": "RightHandThumb3", "DEF-f_index.01.R": "RightHandIndex1", "DEF-f_index.02.R": "RightHandIndex2", "DEF-f_index.03.R": "RightHandIndex3", "DEF-f_middle.01.R": "RightHandMiddle1", "DEF-f_middle.02.R": "RightHandMiddle2", "DEF-f_middle.03.R": "RightHandMiddle3", "DEF-f_ring.01.R": "RightHandRing1", "DEF-f_ring.02.R": "RightHandRing2", "DEF-f_ring.03.R": "RightHandRing3", "DEF-f_pinky.01.R": "RightHandPinky1", "DEF-f_pinky.02.R": "RightHandPinky2", "DEF-f_pinky.03.R": "RightHandPinky3", "DEF-thigh.L": "LeftUpLeg", "DEF-shin.L": "LeftLeg", "DEF-foot.L": "LeftFoot", "DEF-toe.L": "LeftToeBase", "DEF-thigh.R": "RightUpLeg", "DEF-shin.R": "RightLeg", "DEF-foot.R": "RightFoot", "DEF-toe.R": "RightToeBase" } print("Bone mapping loaded.") # Rename original actions to [name]_old for action in list(bpy.data.actions): if not action.name.endswith("_old"): action.name = f"{action.name}_old" # Retarget animations for action in bpy.data.actions: if not action.name.endswith("_old"): continue print("Retargeting:", action.name) new_action = action.copy() new_action.name = action.name.replace("_old", "") for fcurve in new_action.fcurves: path = fcurve.data_path for src_bone, tgt_bone in bone_map.items(): if f'pose.bones["{src_bone}"]' in path: fcurve.data_path = path.replace(src_bone, tgt_bone) if not arm_target.animation_data: arm_target.animation_data_create() arm_target.animation_data.action = new_action # Remove old actions for action in list(bpy.data.actions): if action.name.endswith("_old"): bpy.data.actions.remove(action) # Rotate armature and children 180 degrees around Z axis print("Rotating target armature and children...") bpy.ops.object.select_all(action='DESELECT') arm_target.select_set(True) for child in arm_target.children: child.select_set(True) bpy.context.view_layer.objects.active = arm_target for obj in [arm_target] + list(arm_target.children): obj.rotation_euler[2] += 3.14159 # 180 degrees in radians bpy.context.view_layer.objects.active = obj bpy.ops.object.transform_apply(location=False, rotation=True, scale=False) # Delete source model print("Deleting source...") bpy.ops.object.select_all(action='DESELECT') arm_source.select_set(True) for child in arm_source.children: child.select_set(True) bpy.ops.object.delete() # Export target print("Exporting target with animations...") bpy.ops.object.select_all(action='DESELECT') arm_target.select_set(True) @@ -151,5 +116,4 @@ bpy.context.view_layer.objects.active = arm_target bpy.ops.export_scene.gltf(filepath=out_file, export_format='GLB', use_selection=True) print("DONE. Exported to:", out_file) -
avramovic created this gist
Oct 3, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,155 @@ import bpy, sys, os argv = sys.argv argv = argv[argv.index("--") + 1:] src_file = os.path.abspath(argv[0]) tgt_file = os.path.abspath(argv[1]) out_file = os.path.abspath(argv[2]) print("Source:", src_file) print("Target:", tgt_file) print("Output:", out_file) # Reset scene bpy.ops.wm.read_factory_settings(use_empty=True) # Import source print("Importing source...") bpy.ops.import_scene.gltf(filepath=src_file) # Find source armature arm_source = None for obj in bpy.context.scene.objects: if obj.type == "ARMATURE": arm_source = obj break if not arm_source: raise Exception("No armature in source file") print("Source armature:", arm_source.name) # Import target (mesh for retarget) print("Importing target...") bpy.ops.import_scene.gltf(filepath=tgt_file) arm_target = None for obj in bpy.context.scene.objects: if obj.type == "ARMATURE" and obj != arm_source: arm_target = obj break if not arm_target: raise Exception("No armature in target file") print("Target armature:", arm_target.name) # Bone map bone_map = { # Root / Spine "DEF-hips": "Hips", "DEF-spine.001": "Spine", "DEF-spine.002": "Spine1", "DEF-spine.003": "Spine2", "DEF-neck": "Neck", "DEF-head": "Head", # Left arm "DEF-shoulder.L": "LeftShoulder", "DEF-upper_arm.L": "LeftArm", "DEF-forearm.L": "LeftForeArm", "DEF-hand.L": "LeftHand", "DEF-thumb.01.L": "LeftHandThumb1", "DEF-thumb.02.L": "LeftHandThumb2", "DEF-thumb.03.L": "LeftHandThumb3", "DEF-f_index.01.L": "LeftHandIndex1", "DEF-f_index.02.L": "LeftHandIndex2", "DEF-f_index.03.L": "LeftHandIndex3", "DEF-f_middle.01.L": "LeftHandMiddle1", "DEF-f_middle.02.L": "LeftHandMiddle2", "DEF-f_middle.03.L": "LeftHandMiddle3", "DEF-f_ring.01.L": "LeftHandRing1", "DEF-f_ring.02.L": "LeftHandRing2", "DEF-f_ring.03.L": "LeftHandRing3", "DEF-f_pinky.01.L": "LeftHandPinky1", "DEF-f_pinky.02.L": "LeftHandPinky2", "DEF-f_pinky.03.L": "LeftHandPinky3", # Right arm "DEF-shoulder.R": "RightShoulder", "DEF-upper_arm.R": "RightArm", "DEF-forearm.R": "RightForeArm", "DEF-hand.R": "RightHand", "DEF-thumb.01.R": "RightHandThumb1", "DEF-thumb.02.R": "RightHandThumb2", "DEF-thumb.03.R": "RightHandThumb3", "DEF-f_index.01.R": "RightHandIndex1", "DEF-f_index.02.R": "RightHandIndex2", "DEF-f_index.03.R": "RightHandIndex3", "DEF-f_middle.01.R": "RightHandMiddle1", "DEF-f_middle.02.R": "RightHandMiddle2", "DEF-f_middle.03.R": "RightHandMiddle3", "DEF-f_ring.01.R": "RightHandRing1", "DEF-f_ring.02.R": "RightHandRing2", "DEF-f_ring.03.R": "RightHandRing3", "DEF-f_pinky.01.R": "RightHandPinky1", "DEF-f_pinky.02.R": "RightHandPinky2", "DEF-f_pinky.03.R": "RightHandPinky3", # Legs "DEF-thigh.L": "LeftUpLeg", "DEF-shin.L": "LeftLeg", "DEF-foot.L": "LeftFoot", "DEF-toe.L": "LeftToeBase", "DEF-thigh.R": "RightUpLeg", "DEF-shin.R": "RightLeg", "DEF-foot.R": "RightFoot", "DEF-toe.R": "RightToeBase", } print("Bone mapping:", bone_map) # Copy all animations for action in bpy.data.actions: print("Copying action:", action.name) new_action = action.copy() new_action.name = f"{action.name}_retarget" for fcurve in new_action.fcurves: path = fcurve.data_path for src_bone, tgt_bone in bone_map.items(): if src_bone in path: fcurve.data_path = path.replace(src_bone, tgt_bone) if not arm_target.animation_data: arm_target.animation_data_create() arm_target.animation_data.action = new_action # Remove source model print("Deleting source...") bpy.ops.object.select_all(action='DESELECT') arm_source.select_set(True) for child in arm_source.children: child.select_set(True) bpy.ops.object.delete() # Exportuj only target print("Exporting target with animations...") bpy.ops.object.select_all(action='DESELECT') arm_target.select_set(True) for child in arm_target.children: child.select_set(True) bpy.context.view_layer.objects.active = arm_target bpy.ops.export_scene.gltf(filepath=out_file, export_format='GLB', use_selection=True) print("DONE. Exported to:", out_file)