diff options
author | Benjy Cook <benjycook@hotmail.com> | 2011-08-04 02:26:59 +0400 |
---|---|---|
committer | Benjy Cook <benjycook@hotmail.com> | 2011-08-04 02:26:59 +0400 |
commit | ecd4b869828bc5ed7e3d00ac8dc9e93832f2c156 (patch) | |
tree | 705bad2f697c7670112e5c0943827d9bf1702b9c /release/scripts | |
parent | cbdc67e2e81cb136a0dca2218dd0ccb6ecc557ca (diff) |
Initial coding of path editing operator. Still needs some work, but all the basic functionality is there. Select a path and the stride bone (as active) and it will reparameterize the path to propel the armature forward in the same magnitude of the original
Diffstat (limited to 'release/scripts')
-rw-r--r-- | release/scripts/modules/mocap_tools.py | 61 | ||||
-rw-r--r-- | release/scripts/startup/ui_mocap.py | 33 |
2 files changed, 89 insertions, 5 deletions
diff --git a/release/scripts/modules/mocap_tools.py b/release/scripts/modules/mocap_tools.py index 703db4477ba..20163cd46b8 100644 --- a/release/scripts/modules/mocap_tools.py +++ b/release/scripts/modules/mocap_tools.py @@ -81,6 +81,9 @@ class NdVector: def y(self): return self.vec[1] + def resize_2d(self): + return Vector((self.x, self.y)) + length = property(vecLength) lengthSq = property(vecLengthSq) x = property(x) @@ -322,7 +325,10 @@ def simplifyCurves(curveGroup, error, reparaError, maxIterations, group_mode): return 0, None for pt in data_pts[s:e + 1]: bezVal = bezierEval(bez, pt.u) - tmpError = (pt.co - bezVal).length / pt.co.length + normalize_error = pt.co.length + if normalize_error == 0: + normalize_error = 1 + tmpError = (pt.co - bezVal).length / normalize_error if tmpError >= maxError: maxError = tmpError maxErrorPt = pt.index @@ -471,10 +477,8 @@ def simplifyCurves(curveGroup, error, reparaError, maxIterations, group_mode): #(e.g. a bone's x,y,z rotation) -def fcurves_simplify(sel_opt="all", error=0.002, group_mode=True): +def fcurves_simplify(context, obj, sel_opt="all", error=0.002, group_mode=True): # main vars - context = bpy.context - obj = context.active_object fcurves = obj.animation_data.action.fcurves if sel_opt == "sel": @@ -706,3 +710,52 @@ def limit_dof_toggle_off(context, enduser_obj): existingConstraint = [constraint for constraint in bone.constraints if constraint.name == "DOF Limitation"] if existingConstraint: bone.constraints.remove(existingConstraint[0]) + + +def path_editing(context, stride_obj, path): + y_fcurve = [fcurve for fcurve in stride_obj.animation_data.action.fcurves if fcurve.data_path == "location"][1] + s, e = context.scene.frame_start, context.scene.frame_end # y_fcurve.range() + s = int(s) + e = int(e) + y_s = y_fcurve.evaluate(s) + y_e = y_fcurve.evaluate(e) + direction = (y_e - y_s) / abs(y_e - y_s) + existing_cons = [constraint for constraint in stride_obj.constraints if constraint.type == "FOLLOW_PATH"] + for cons in existing_cons: + stride_obj.constraints.remove(cons) + path_cons = stride_obj.constraints.new("FOLLOW_PATH") + if direction < 0: + path_cons.forward_axis = "TRACK_NEGATIVE_Y" + else: + path_cons.forward_axis = "FORWARD_Y" + path_cons.target = path + path_cons.use_curve_follow = True + path.data.path_duration = e - s + try: + path.data.animation_data.action.fcurves + except AttributeError: + path.data.keyframe_insert("eval_time", frame=0) + eval_time_fcurve = [fcurve for fcurve in path.data.animation_data.action.fcurves if fcurve.data_path == "eval_time"] + eval_time_fcurve = eval_time_fcurve[0] + totalLength = 0 + parameterization = {} + print("evaluating curve") + for t in range(s, e - 1): + if s == t: + chordLength = 0 + else: + chordLength = (y_fcurve.evaluate(t) - y_fcurve.evaluate(t + 1)) + totalLength += chordLength + parameterization[t] = totalLength + for t in range(s + 1, e - 1): + if totalLength == 0: + print("no forward motion") + parameterization[t] /= totalLength + parameterization[t] *= e - s + parameterization[e] = e - s + for t in parameterization.keys(): + eval_time_fcurve.keyframe_points.insert(frame=t, value=parameterization[t]) + error = 0.01 + reparaError = error * 32 + maxIterations = 16 + print("finished path editing") diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py index ac063a3a0cc..03d173df7a6 100644 --- a/release/scripts/startup/ui_mocap.py +++ b/release/scripts/startup/ui_mocap.py @@ -304,6 +304,18 @@ class MocapConstraintsPanel(bpy.types.Panel): layout.separator() +class ExtraToolsPanel(bpy.types.Panel): + # Motion capture retargeting panel + bl_label = "Extra Mocap Tools" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "object" + + def draw(self, context): + layout = self.layout + layout.operator('mocap.pathediting', text="Follow Path") + + class OBJECT_OT_RetargetButton(bpy.types.Operator): '''Retarget animation from selected armature to active armature ''' bl_idname = "mocap.retarget" @@ -383,7 +395,7 @@ class OBJECT_OT_ConvertSamplesButton(bpy.types.Operator): bl_label = "Converts samples / simplifies keyframes to beziers" def execute(self, context): - mocap_tools.fcurves_simplify() + mocap_tools.fcurves_simplify(context, context.active_object) return {"FINISHED"} @classmethod @@ -598,6 +610,25 @@ class OBJECT_OT_GuessHierachyMapping(bpy.types.Operator): return False +class OBJECT_OT_PathEditing(bpy.types.Operator): + '''Sets active object (stride object) to follow the selected curve''' + bl_idname = "mocap.pathediting" + bl_label = "Sets active object (stride object) to follow the selected curve" + + def execute(self, context): + path = [obj for obj in context.selected_objects if obj != context.active_object][0] + mocap_tools.path_editing(context, context.active_object, path) + return {"FINISHED"} + + @classmethod + def poll(cls, context): + if context.active_object: + selected_objs = [obj for obj in context.selected_objects if obj != context.active_object] + return selected_objs + else: + return False + + def register(): bpy.utils.register_module(__name__) |