diff options
author | Benjy Cook <benjycook@hotmail.com> | 2011-08-08 15:09:56 +0400 |
---|---|---|
committer | Benjy Cook <benjycook@hotmail.com> | 2011-08-08 15:09:56 +0400 |
commit | 60eec89cda50360c8fc68f9d3d6dc18e5c6633b1 (patch) | |
tree | d16e81a8bab6d24e0ccd77e09a8893c075f81093 /release/scripts | |
parent | 8883702f8a3b57d0316811e9412bd46ce0dd9c0d (diff) |
Created property systems for multiple retargets on a single armature, for this type of use and animation stitching. Also contains some placeholder UI and code for animation stitching.
Diffstat (limited to 'release/scripts')
-rw-r--r-- | release/scripts/modules/mocap_constraints.py | 8 | ||||
-rw-r--r-- | release/scripts/modules/mocap_tools.py | 8 | ||||
-rw-r--r-- | release/scripts/modules/retarget.py | 68 | ||||
-rw-r--r-- | release/scripts/startup/ui_mocap.py | 69 |
4 files changed, 126 insertions, 27 deletions
diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py index 75afbe62231..63e46f99349 100644 --- a/release/scripts/modules/mocap_constraints.py +++ b/release/scripts/modules/mocap_constraints.py @@ -59,7 +59,7 @@ def addNewConstraint(m_constraint, cons_obj): c_type = "LIMIT_LOCATION" #create and store the new constraint within m_constraint real_constraint = cons_obj.constraints.new(c_type) - real_constraint.name = "Mocap fix " + str(len(cons_obj.constraints)) + real_constraint.name = "Auto fixes " + str(len(cons_obj.constraints)) m_constraint.real_constraint_bone = consObjToBone(cons_obj) m_constraint.real_constraint = real_constraint.name #set the rest of the constraint properties @@ -364,7 +364,8 @@ def bakeAllConstraints(obj, s_frame, e_frame, bones): simpleBake += [end_bone] for bone in selectedBones: bone.bone.select = True - constraintTrack = obj.animation_data.nla_tracks["Mocap fixes"] + tracks = [track for track in obj.data.mocapNLATracks if track.active][0] + constraintTrack = obj.animation_data.nla_tracks[tracks.auto_fix_track] constraintStrip = constraintTrack.strips[0] constraintStrip.action_frame_start = s_frame constraintStrip.action_frame_end = e_frame @@ -403,7 +404,8 @@ def unbakeConstraints(context): obj = context.active_object bones = obj.pose.bones scene = bpy.context.scene - constraintTrack = obj.animation_data.nla_tracks["Mocap fixes"] + tracks = obj.data.mocapNLATracks[obj.animation_data.action] + constraintTrack = obj.animation_data.nla_tracks[tracks.auto_fix_track] constraintStrip = constraintTrack.strips[0] action = constraintStrip.action # delete the fcurves on the strip diff --git a/release/scripts/modules/mocap_tools.py b/release/scripts/modules/mocap_tools.py index 17f9e590d10..fa307a36a57 100644 --- a/release/scripts/modules/mocap_tools.py +++ b/release/scripts/modules/mocap_tools.py @@ -757,3 +757,11 @@ def path_editing(context, stride_obj, path): eval_time_fcurve.keyframe_points.insert(frame=t, value=parameterization[t]) y_fcurve.mute = True print("finished path editing") + + +def anim_stitch(context, enduser_obj): + stitch_settings = enduser_obj.data.stitch_settings + action_1 = stitch_settings.first_action + action_2 = stitch_settings.second_action + TrackNamesA = enduser_obj.data.mocapNLATracks[action_1] + TrackNamesB = enduser_obj.data.mocapNLATracks[action_2] diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py index 629e363b918..b3c386e6c4d 100644 --- a/release/scripts/modules/retarget.py +++ b/release/scripts/modules/retarget.py @@ -272,21 +272,31 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame if endV.length != 0: linearAvg.append(hipV.length / endV.length) - bpy.ops.object.add() - stride_bone = bpy.context.active_object - stride_bone.name = "stride_bone" - + action_name = performer_obj.animation_data.action.name + #if you have a parent, and that parent is a previously created stride bone + if enduser_obj.parent: + stride_action = bpy.data.actions.new("Stride Bone " + action_name) + stride_bone = enduser_obj.parent + stride_bone.animation_data.action = stride_action + else: + bpy.ops.object.add() + stride_bone = bpy.context.active_object + stride_bone.name = "stride_bone" + print(stride_bone) + stride_bone.location = Vector((0, 0, 0)) if linearAvg: #determine the average change in scale needed avg = sum(linearAvg) / len(linearAvg) scene.frame_set(s_frame) - initialPos = (tailLoc(perf_bones[perfRoot]) / avg) + initialPos = (tailLoc(perf_bones[perfRoot]) / avg) + stride_bone.location for t in range(s_frame, e_frame): scene.frame_set(t) #calculate the new position, by dividing by the found ratio between performer and enduser newTranslation = (tailLoc(perf_bones[perfRoot]) / avg) stride_bone.location = enduser_obj_mat * (newTranslation - initialPos) stride_bone.keyframe_insert("location") + stride_bone.animation_data.action.name = ("Stride Bone " + action_name) + return stride_bone @@ -299,7 +309,7 @@ def IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene): # set constraint target to corresponding empty if targetless, # if not, keyframe current target to corresponding empty perf_bone = pose_bone.bone.reverseMap[-1].name - orgLocTrg = originalLocationTarget(pose_bone) + orgLocTrg = originalLocationTarget(pose_bone, enduser_obj) if not ik_constraint.target: ik_constraint.target = orgLocTrg target = orgLocTrg @@ -322,6 +332,7 @@ def IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene): target.location = final_loc target.keyframe_insert("location") ik_constraint.mute = False + scene.frame_set(s_frame) def turnOffIK(enduser_obj): @@ -358,44 +369,59 @@ def restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, str empty = bpy.data.objects[pose_bone.name + "Org"] empty.parent = stride_bone performer_obj.matrix_world = perf_obj_mat - enduser_obj.matrix_world = enduser_obj_mat enduser_obj.parent = stride_bone + enduser_obj.matrix_world = enduser_obj_mat #create (or return if exists) the related IK empty to the bone -def originalLocationTarget(end_bone): +def originalLocationTarget(end_bone, enduser_obj): if not end_bone.name + "Org" in bpy.data.objects: bpy.ops.object.add() empty = bpy.context.active_object empty.name = end_bone.name + "Org" empty.empty_draw_size = 0.1 - #empty.parent = enduser_obj + empty.parent = enduser_obj empty = bpy.data.objects[end_bone.name + "Org"] return empty #create the specified NLA setup for base animation, constraints and tweak layer. -def NLASystemInitialize(enduser_obj, s_frame): +def NLASystemInitialize(enduser_obj, s_frame, name): anim_data = enduser_obj.animation_data + if not name in enduser_obj.data.mocapNLATracks: + NLATracks = enduser_obj.data.mocapNLATracks.add() + NLATracks.name = name + else: + NLATracks = enduser_obj.data.mocapNLATracks[name] + for track in enduser_obj.data.mocapNLATracks: + track.active = False mocapAction = anim_data.action - mocapAction.name = "Base Mocap" + mocapAction.name = "Base " + name anim_data.use_nla = True + for track in anim_data.nla_tracks: + anim_data.nla_tracks.remove(track) mocapTrack = anim_data.nla_tracks.new() - mocapTrack.name = "Base Mocap Track" - mocapStrip = mocapTrack.strips.new("Base Mocap", s_frame, mocapAction) + mocapTrack.name = "Base " + name + NLATracks.base_track = mocapTrack.name + mocapStrip = mocapTrack.strips.new("Base " + name, s_frame, mocapAction) constraintTrack = anim_data.nla_tracks.new() - constraintTrack.name = "Mocap fixes" - constraintAction = bpy.data.actions.new("Mocap fixes") - constraintStrip = constraintTrack.strips.new("Mocap fixes", s_frame, constraintAction) + constraintTrack.name = "Auto fixes " + name + NLATracks.auto_fix_track = constraintTrack.name + constraintAction = bpy.data.actions.new("Auto fixes " + name) + constraintStrip = constraintTrack.strips.new("Auto fixes " + name, s_frame, constraintAction) constraintStrip.extrapolation = "NOTHING" userTrack = anim_data.nla_tracks.new() - userTrack.name = "Mocap manual fix" - userAction = bpy.data.actions.new("Mocap manual fix") - userStrip = userTrack.strips.new("Mocap manual fix", s_frame, userAction) + userTrack.name = "Manual fixes " + name + NLATracks.manual_fix_track = userTrack.name + if enduser_obj.parent.animation_data: + NLATracks.stride_action = enduser_obj.parent.animation_data.action.name + userAction = bpy.data.actions.new("Manual fixes " + name) + userStrip = userTrack.strips.new("Manual fixes " + name, s_frame, userAction) userStrip.extrapolation = "HOLD" #userStrip.blend_type = "MULITPLY" - doesn't work due to work, will be activated soon anim_data.nla_tracks.active = constraintTrack - anim_data.action = constraintAction + NLATracks.active = True + #anim_data.action = constraintAction anim_data.action_extrapolation = "NOTHING" @@ -419,7 +445,7 @@ def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame): bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_name(name=inter_obj.name, extend=False) bpy.ops.object.delete() - NLASystemInitialize(enduser_obj, s_frame) + NLASystemInitialize(enduser_obj, s_frame, performer_obj.animation_data.action.name) print("retargeting done!") if __name__ == "__main__": diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index 8ef4c1e7591..3d034b0047a 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -110,6 +110,35 @@ bpy.utils.register_class(MocapConstraint) bpy.types.Armature.mocap_constraints = bpy.props.CollectionProperty(type=MocapConstraint) + +class AnimationStitchSettings(bpy.types.PropertyGroup): + first_action = bpy.props.StringProperty(name="Action 1", + description="First action in stitch") + second_action = bpy.props.StringProperty(name="Action 2", + description="Second action in stitch") + blend_frame = bpy.props.IntProperty(name="Stitch frame", + description="Frame to locate stitch on") + blend_amount = bpy.props.IntProperty(name="Blend amount", + description="Size of blending transitiion, on both sides of the stitch", + default=10) + +bpy.utils.register_class(AnimationStitchSettings) + + +class MocapNLATracks(bpy.types.PropertyGroup): + name = bpy.props.StringProperty() + active = bpy.props.BoolProperty() + base_track = bpy.props.StringProperty() + auto_fix_track = bpy.props.StringProperty() + manual_fix_track = bpy.props.StringProperty() + stride_action = bpy.props.StringProperty() + +bpy.utils.register_class(MocapNLATracks) + +bpy.types.Armature.stitch_settings = bpy.props.PointerProperty(type=AnimationStitchSettings) + +bpy.types.Armature.mocapNLATracks = bpy.props.CollectionProperty(type=MocapNLATracks) + #Update function for IK functionality. Is called when IK prop checkboxes are toggled. @@ -246,6 +275,7 @@ class MocapPanel(bpy.types.Panel): mapRow = self.layout.row() mapRow.operator("mocap.savemapping", text='Save mapping') mapRow.operator("mocap.loadmapping", text='Load mapping') + self.layout.prop(data=performer_obj.animation_data.action, property='name', text='Action Name') self.layout.operator("mocap.retarget", text='RETARGET!') @@ -315,6 +345,16 @@ class ExtraToolsPanel(bpy.types.Panel): def draw(self, context): layout = self.layout layout.operator('mocap.pathediting', text="Follow Path") + layout.label("Animation Stitching") + activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) + if activeIsArmature: + enduser_arm = context.active_object.data + settings = enduser_arm.stitch_settings + layout.prop_search(settings, "first_action", enduser_arm, "mocapNLATracks") + layout.prop_search(settings, "second_action", enduser_arm, "mocapNLATracks") + layout.prop(settings, "blend_frame") + layout.prop(settings, "blend_amount") + layout.operator('mocap.animstitch', text="Stitch Animations") class OBJECT_OT_RetargetButton(bpy.types.Operator): @@ -323,15 +363,18 @@ class OBJECT_OT_RetargetButton(bpy.types.Operator): bl_label = "Retargets active action from Performer to Enduser" def execute(self, context): + scene = context.scene + s_frame = scene.frame_start + e_frame = scene.frame_end enduser_obj = context.active_object performer_obj = [obj for obj in context.selected_objects if obj != enduser_obj] if enduser_obj is None or len(performer_obj) != 1: print("Need active and selected armatures") else: performer_obj = performer_obj[0] - scene = context.scene - s_frame = scene.frame_start - e_frame = scene.frame_end + s_frame, e_frame = performer_obj.animation_data.action.frame_range + s_frame = int(s_frame) + e_frame = int(e_frame) retarget.totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame) return {"FINISHED"} @@ -645,6 +688,26 @@ class OBJECT_OT_PathEditing(bpy.types.Operator): return False +class OBJECT_OT_AnimationStitchingButton(bpy.types.Operator): + '''Stitches two defined animations into a single one via alignment of NLA Tracks''' + bl_idname = "mocap.animstitch" + bl_label = "Stitches two defined animations into a single one via alignment of NLA Tracks" + + def execute(self, context): + mocap_tools.anim_stitch(context, context.active_object) + return {"FINISHED"} + + @classmethod + def poll(cls, context): + activeIsArmature = False + if context.active_object: + activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature) + if activeIsArmature: + stitch_settings = context.active_object.data.stitch_settings + return (stitch_settings.first_action and stitch_settings.second_action) + return False + + def register(): bpy.utils.register_module(__name__) |