Skip to content

Commit e05965c

Browse files
committed
broken commit, attempting to add root bone insertion feature which doesn't just copy hip bones.
1 parent 169468c commit e05965c

2 files changed

Lines changed: 185 additions & 4 deletions

File tree

__init__.py

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
bl_info = {
2525
"name": "Mixamo Root",
2626
"author": "Richard Perry, Johngoss725",
27-
"version": (1, 1, 2),
27+
"version": (1, 2, 2),
2828
"blender": (2, 80, 0),
2929
"location": "3D View > UI (Right Panel) > Mixamo Tab",
3030
"description": ("Script to bake insert root motion bone for Mixamo Animations"),
@@ -148,6 +148,27 @@ def execute(self, context):
148148
mixamoroot.apply_all_anims(delete_applied_armatures=delete_applied_armatures, control_rig=control_rig, push_nla=push_nla)
149149
return{ 'FINISHED'}
150150

151+
class OBJECT_OT_AddRootNLA(bpy.types.Operator):
152+
'''Operator for adding a root bone to all animations to in the NLA, including keyframes'''
153+
bl_idname = "mixamo.addrootnla"
154+
bl_label = "Add Root"
155+
bl_description = "Adds a root bone to all animation strips in the NLA for the selected armature, iterating through every keyframe and copying the hip position. Sets the Z coordinate to a minimum of 0"
156+
157+
# Works on the selected armature only
158+
def execute(self, context):
159+
mixamo = context.scene.mixamo
160+
hip_name = mixamo.hip_name
161+
root_name = mixamo.root_name
162+
name_prefix = mixamo.name_prefix
163+
if hip_name == '':
164+
self.report({'ERROR_INVALID_INPUT'}, "Error: no Hip Bone Name set.")
165+
return{ 'CANCELLED'}
166+
if root_name == '':
167+
self.report({'ERROR_INVALID_INPUT'}, "Error: no Root Bone Name set.")
168+
return{ 'CANCELLED'}
169+
mixamoroot.add_root_bone_nla(root_bone_name=root_name, hip_bone_name=hip_name, name_prefix=name_prefix)
170+
return{ 'FINISHED'}
171+
151172
class MIXAMOCONV_VIEW_3D_PT_mixamoroot(bpy.types.Panel):
152173
"""Creates a Tab in the Toolshelve in 3D_View"""
153174
bl_label = "Mixamo Root"
@@ -197,11 +218,16 @@ def draw(self, context):
197218
row = box.row()
198219
# box.prop(scene.mixamo, "mixamo.applyanims") # todo
199220
row.operator("mixamo.applyanims")
221+
row = box.row()
222+
row.scale_y = 2.0
223+
row.operator("mixamo.addrootnla")
224+
status_row = box.row()
200225
# status_row = box.row()
201226

202227
classes = (
203228
OBJECT_OT_ImportAnimations,
204229
OBJECT_OT_ApplyAnimations,
230+
OBJECT_OT_AddRootNLA,
205231
MIXAMOCONV_VIEW_3D_PT_mixamoroot,
206232
)
207233

@@ -217,7 +243,8 @@ def register():
217243
'''
218244
bpy.utils.register_class(OBJECT_OT_ImportAnimations)
219245
bpy.utils.register_class(OBJECT_OT_ApplyAnimations)
220-
bpy.utils.unregister_class(MixamorootPanel)
246+
bpy.utils.register_class(OBJECT_OT_AddRootNLA)
247+
bpy.utils.register_class(MixamorootPanel)
221248
'''
222249

223250
def unregister():
@@ -226,8 +253,9 @@ def unregister():
226253
bpy.utils.unregister_class(MixamoPropertyGroup)
227254
'''
228255
bpy.utils.unregister_class(MixamoPropertyGroup)
229-
bpy.utils.register_class(OBJECT_OT_ImportAnimations)
230-
bpy.utils.register_class(OBJECT_OT_ApplyAnimations)
256+
bpy.utils.uregister_class(OBJECT_OT_ImportAnimations)
257+
bpy.utils.uregister_class(OBJECT_OT_ApplyAnimations)
258+
bpy.utils.unregister_class(OBJECT_OT_AddRootNLA)
231259
bpy.utils.unregister_class(MixamorootPanel)
232260
'''
233261
del bpy.types.Scene.mixamo_control_rig

mixamoroot.py

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,144 @@ def copyHips(root_bone_name="Root", hip_bone_name="mixamorig:Hips", name_prefix=
116116
bpy.context.area.ui_type = 'VIEW_3D'
117117
bpy.ops.object.mode_set(mode='OBJECT')
118118

119+
def fix_bones_nla(remove_prefix=False, name_prefix="mixamorig:"):
120+
bpy.ops.object.mode_set(mode = 'OBJECT')
121+
122+
if not bpy.ops.object:
123+
log.warning('[Mixamo Root] Could not find amature object, please select the armature')
124+
125+
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
126+
bpy.context.object.show_in_front = True
127+
128+
def scale_all_nla(armature):
129+
bpy.ops.object.mode_set(mode='OBJECT')
130+
131+
# prev_context=bpy.context.area.type
132+
133+
for track in [x for x in armature.animation_data.nla_tracks]:
134+
bpy.context.active_nla_track = track
135+
for strip in track.strips:
136+
bpy.context.active_nla_strip = strip
137+
print(bpy.context.active_nla_strip)
138+
139+
140+
bpy.ops.object.mode_set(mode='POSE')
141+
bpy.ops.pose.select_all(action='SELECT')
142+
bpy.context.area.type = 'GRAPH_EDITOR'
143+
bpy.context.space_data.dopesheet.filter_text = "Location"
144+
bpy.context.space_data.pivot_point = 'CURSOR'
145+
bpy.context.space_data.dopesheet.use_filter_invert = False
146+
147+
bpy.ops.anim.channels_select_all(action='SELECT')
148+
149+
bpy.ops.transform.resize(value=(1, 0.01, 1), orient_type='GLOBAL',
150+
orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)),
151+
orient_matrix_type='GLOBAL',
152+
constraint_axis=(False, True, False),
153+
mirror=True, use_proportional_edit=False,
154+
proportional_edit_falloff='SMOOTH',
155+
proportional_size=1,
156+
use_proportional_connected=False,
157+
use_proportional_projected=False)
158+
159+
def copy_hips_nla(root_bone_name="Root", hip_bone_name="mixamorig:Hips", name_prefix="mixamorig:"):
160+
hip_bone_name="Ctrl_Hips"
161+
bpy.ops.object.mode_set(mode='POSE')
162+
previous_context = bpy.context.area.ui_type
163+
bpy.ops.pose.select_all(action='DESELECT')
164+
while False:
165+
#SELECT OUR ROOT MOTION BONE
166+
# bpy.context.object.pose.bones[name_prefix + root_bone_name].bone.select = True
167+
168+
# bpy.ops.nla.tweakmode_enter()
169+
# bpy.context.area.ui_type = 'FCURVES'
170+
171+
# # SET FRAME TO ZERO
172+
# bpy.ops.graph.cursor_set(frame=0.0, value=0.0)
173+
# #ADD NEW KEYFRAME
174+
# bpy.ops.anim.keyframe_insert_menu(type='Location')
175+
# #SELECT ONLY HIPS AND LOCTAIUON GRAPH DATA
176+
# bpy.ops.pose.select_all(action='DESELECT')
177+
# bpy.context.object.pose.bones[hip_bone_name].bone.select = True
178+
# bpy.context.area.ui_type = 'DOPESHEET'
179+
# bpy.context.space_data.dopesheet.filter_text = "Location"
180+
# bpy.context.area.ui_type = 'FCURVES'
181+
# #COPY THE LOCATION VALUES OF THE HIPS AND DELETE THEM
182+
# bpy.ops.graph.copy()
183+
# bpy.ops.graph.select_all(action='DESELECT')
184+
185+
# myFcurves = bpy.context.object.animation_data.action.fcurves
186+
187+
# for i in myFcurves:
188+
# hip_bone_fcvurve = 'pose.bones["'+hip_bone_name+'"].location'
189+
# if str(i.data_path)==hip_bone_fcvurve:
190+
# myFcurves.remove(i)
191+
192+
# bpy.ops.pose.select_all(action='DESELECT')
193+
# bpy.context.object.pose.bones[name_prefix + root_bone_name].bone.select = True
194+
# bpy.ops.graph.paste()
195+
196+
# for animation data in object
197+
# for
198+
pass
199+
200+
for track in bpy.context.object.animation_data.nla_tracks:
201+
bpy.context.object.animation_data.nla_tracks.active = track
202+
for strip in track.strips:
203+
bpy.context.object.pose.bones[name_prefix + root_bone_name].bone.select = True
204+
bpy.context.area.ui_type = 'NLA_EDITOR'
205+
bpy.ops.nla.tweakmode_enter()
206+
bpy.context.area.ui_type = 'FCURVES'
207+
hip_curves = [fc for fc in strip.fcurves if hip_bone_name in fc.data_path and fc.data_path.startswith('location')]
208+
209+
# Copy Hips to root
210+
## Insert keyframe for root bone
211+
start_frame = strip.action.frame_range[0]
212+
# frame sets the x axis cursor (determines the frame, and value the y axis cursor, which is the amplitude of the curve)
213+
bpy.ops.graph.cursor_set(frame=start_frame, value=0.0)
214+
bpy.ops.anim.keyframe_insert_menu(type='Location')
215+
bpy.ops.pose.select_all(action='DESELECT')
216+
217+
## Copy Location fcruves
218+
bpy.context.object.pose.bones[hip_bone_name].bone.select = True
219+
bpy.context.area.ui_type = 'DOPESHEET'
220+
bpy.context.space_data.dopesheet.filter_text = "Location"
221+
bpy.context.area.ui_type = 'FCURVES'
222+
bpy.ops.graph.copy()
223+
bpy.ops.graph.select_all(action='DESELECT')
224+
225+
## We want to delete the hips locations
226+
allFcurves = strip.fcurves
227+
for fc in hip_curves:
228+
allFcurves.remove(fc)
229+
230+
## Paste location fcurves to the root bone
231+
bpy.ops.pose.select_all(action='DESELECT')
232+
bpy.context.object.pose.bones[name_prefix + root_bone_name].bone.select = True
233+
bpy.ops.graph.paste()
234+
235+
236+
loc_fcurves = [fc for fc in strip.fcurves if root_bone_name in fc.data_path and fc.data_path.startswith('location')]
237+
238+
# Update Root Bone
239+
# set z of root to min 0 (not negative).
240+
for fc in loc_fcurves:
241+
# Z axis location curve
242+
if fc.array_index == 2:
243+
for kp in fc.keyframe_points:
244+
kp.co.z = min(0, abs(kp.co.z))
245+
246+
# Delete rotation curves for x(0) and y(1) axis. Should we delet Z rotation too?
247+
# rot_fcurves = [fc for fc in strip.fcurves if root_bone_name in fc.data_path and fc.data_path.startswith('rotation') and (fc.array_index == 0 or fc.array_index == 1)]
248+
# for fc in rot_fcurves:
249+
# strip.fcurves.remove(fc)
250+
# while(rot_fcurves):
251+
# fc = rot_fcurves.pop()
252+
# strip.fcurves.remove(fc)
253+
bpy.context.area.ui_type = 'NLA_EDITOR'
254+
bpy.ops.nla.tweakmode_exit()
255+
bpy.context.area.ui_type = previous_context
256+
bpy.ops.object.mode_set(mode='OBJECT')
119257

120258
def deleteArmature(imported_objects=set()):
121259
armature = None
@@ -164,6 +302,21 @@ def add_root_bone(root_bone_name="Root", hip_bone_name="mixamorig:Hips", remove_
164302
scaleAll()
165303
copyHips(root_bone_name=root_bone_name, hip_bone_name=hip_bone_name, name_prefix=name_prefix)
166304

305+
def add_root_bone_nla(root_bone_name="Root", hip_bone_name="mixamorig:Hips", name_prefix="mixamorig:"):#remove_prefix=False, name_prefix="mixamorig:"):
306+
armature = bpy.context.selected_objects[0]
307+
bpy.ops.object.mode_set(mode='EDIT')
308+
309+
# Add root bone to edit bones
310+
root_bone = armature.data.edit_bones.new(name_prefix + root_bone_name)
311+
root_bone.tail.z = .25
312+
313+
armature.data.edit_bones[hip_bone_name].parent = armature.data.edit_bones[name_prefix + root_bone_name]
314+
bpy.ops.object.mode_set(mode='OBJECT')
315+
316+
# fix_bones_nla(remove_prefix=remove_prefix, name_prefix=name_prefix)
317+
# scale_all_nla()
318+
copy_hips_nla(root_bone_name=root_bone_name, hip_bone_name=hip_bone_name, name_prefix=name_prefix)
319+
167320
def push(obj, action, track_name=None, start_frame=0):
168321
# Simulate push :
169322
# * add a track

0 commit comments

Comments
 (0)