|
import bpy |
|
|
|
|
|
bl_info = { |
|
"name": "Mixamo Root Fixer", |
|
"description": "Moves location xz from mixamo hips to root bone", |
|
"author": "Steven Landow", |
|
"version": (1, 0), |
|
"blender": (3, 6, 0), |
|
"category": "Animation", |
|
} |
|
|
|
|
|
class OperatorRootMotionFix(bpy.types.Operator): |
|
bl_idname = "stevenctl.mixamo_root_motion_fix" |
|
bl_label = "Fix Root Motion Bone" |
|
|
|
def execute(self, context): |
|
try: |
|
hip_motion_to_root() |
|
except Exception as e: |
|
self.report({"ERROR"}, e) |
|
return {"FINISHED"} |
|
|
|
|
|
class RootMotionFixPanel(bpy.types.Panel): |
|
bl_label = "Fix Root Motion Bone" |
|
bl_category = "Mixamo Fix" |
|
bl_idname = "stevenctl.mixamo_fix_panel" |
|
|
|
bl_space_type = "VIEW_3D" |
|
bl_region_type = "UI" |
|
|
|
def draw(self, context): |
|
self.layout.operator(OperatorRootMotionFix.bl_idname) |
|
|
|
|
|
def hip_motion_to_root(): |
|
scene = bpy.context.scene |
|
if not scene: |
|
return |
|
obj = bpy.context.active_object |
|
if not obj or obj.type != "ARMATURE": |
|
print("no selected armature") |
|
return |
|
action = obj.animation_data.action |
|
if not action: |
|
print("no selected action") |
|
return |
|
if not obj.pose.bones['mixamorig:Hips']: |
|
print("no hips") |
|
return |
|
if not obj.pose.bones['root']: |
|
print("no root") |
|
return |
|
for frame in range(scene.frame_start, scene.frame_end+1): |
|
scene.frame_set(frame) |
|
root = obj.pose.bones['root'] |
|
hips = obj.pose.bones['mixamorig:Hips'] |
|
xz = hips.location.xz |
|
root.location.xz = xz |
|
root.keyframe_insert("location", frame=frame) |
|
hips.location.xz = (0, 0) |
|
hips.keyframe_insert("location", frame=frame) |
|
|
|
|
|
def register(): |
|
bpy.utils.register_class(OperatorRootMotionFix) |
|
bpy.utils.register_class(RootMotionFixPanel) |
|
|
|
|
|
def unregister(): |
|
bpy.utils.unregister_class(OperatorRootMotionFix) |
|
bpy.utils.unregister_class(RootMotionFixPanel) |