diff options
Diffstat (limited to 'mocap/mocap_tools.py')
-rw-r--r-- | mocap/mocap_tools.py | 63 |
1 files changed, 35 insertions, 28 deletions
diff --git a/mocap/mocap_tools.py b/mocap/mocap_tools.py index 91c92a98..3f910411 100644 --- a/mocap/mocap_tools.py +++ b/mocap/mocap_tools.py @@ -18,7 +18,7 @@ # <pep8 compliant> -from math import sqrt, radians +from math import sqrt, radians, floor, ceil import bpy import time from mathutils import Vector, Matrix @@ -108,6 +108,13 @@ class dataPoint: self.u = u +# Helper to convert from a sampled fcurve back to editable keyframes one. +def make_editable_fcurves(fcurves): + for fc in fcurves: + if fc.sampled_points: + fc.convert_to_keyframes(floor(fc.sampled_points[0].co[0]), ceil(fc.sampled_points[-1].co[0]) + 1) + + #Cross Correlation Function #http://en.wikipedia.org/wiki/Cross_correlation #IN: curvesA, curvesB - bpy_collection/list of fcurves to analyze. Auto-Correlation is when they are the same. @@ -233,7 +240,6 @@ def autoloop_anim(): # group_mode - boolean, indicating wether we should place bezier keyframes on the same x (frame), or optimize each individual curve. #OUT: None. Deletes the existing curves and creates the new beziers. def simplifyCurves(curveGroup, error, reparaError, maxIterations, group_mode): - #Calculates the unit tangent of point v def unitTangent(v, data_pts): tang = NdVector((0, 0, 0, 0, 0)) @@ -416,26 +422,17 @@ def simplifyCurves(curveGroup, error, reparaError, maxIterations, group_mode): #Create data_pts, a list of dataPoint type, each is assigned index i, and an NdVector def createDataPts(curveGroup, group_mode): - data_pts = [] + make_editable_fcurves(curveGroup if group_mode else (curveGroup,)) + if group_mode: print([x.data_path for x in curveGroup]) - for i in range(len(curveGroup[0].keyframe_points)): - x = curveGroup[0].keyframe_points[i].co.x - y1 = curveGroup[0].evaluate(i) - y2 = curveGroup[1].evaluate(i) - y3 = curveGroup[2].evaluate(i) - y4 = 0 - if len(curveGroup) == 4: - y4 = curveGroup[3].evaluate(i) - data_pts.append(dataPoint(i, NdVector((x, y1, y2, y3, y4)))) + comp_cos = (0,) * (4 - len(curveGroup)) # We need to add that number of null cos to get our 5D vector. + kframes = sorted(set(kf.co.x for fc in curveGroup for kf in fc.keyframe_points)) + data_pts = [dataPoint(i, NdVector((fra,) + tuple(fc.evaluate(fra) for fc in curveGroup) + comp_cos)) + for i, fra in enumerate(kframes)] else: - for i in range(len(curveGroup.keyframe_points)): - x = curveGroup.keyframe_points[i].co.x - y1 = curveGroup.keyframe_points[i].co.y - y2 = 0 - y3 = 0 - y4 = 0 - data_pts.append(dataPoint(i, NdVector((x, y1, y2, y3, y4)))) + data_pts = [dataPoint(i, NdVector((kf.co.x, kf.co.y, 0, 0, 0))) + for i, kf in enumerate(curveGroup.keyframe_points)] return data_pts #Recursively fit cubic beziers to the data_pts between s and e @@ -460,8 +457,8 @@ def simplifyCurves(curveGroup, error, reparaError, maxIterations, group_mode): else: bez = fitSingleCubic(data_pts, s, e) - #recalculate max error and point where it occurs - maxError, maxErrorPt = maxErrorAmount(data_pts, bez, s, e) + #recalculate max error and point where it occurs + maxError, maxErrorPt = maxErrorAmount(data_pts, bez, s, e) #repara wasn't enough, we need 2 beziers for this range. #Split the bezier at point of maximum error @@ -479,37 +476,44 @@ def simplifyCurves(curveGroup, error, reparaError, maxIterations, group_mode): if group_mode: for fcurve in curveGroup: for i in range(len(fcurve.keyframe_points) - 1, 0, -1): - fcurve.keyframe_points.remove(fcurve.keyframe_points[i]) + fcurve.keyframe_points.remove(fcurve.keyframe_points[i], fast=True) else: fcurve = curveGroup for i in range(len(fcurve.keyframe_points) - 1, 0, -1): - fcurve.keyframe_points.remove(fcurve.keyframe_points[i]) + fcurve.keyframe_points.remove(fcurve.keyframe_points[i], fast=True) - #insert the calculated beziers to blender data.\ + #insert the calculated beziers to blender data. if group_mode: for fullbez in beziers: for i, fcurve in enumerate(curveGroup): bez = [Vector((vec[0], vec[i + 1])) for vec in fullbez] - newKey = fcurve.keyframe_points.insert(frame=bez[0].x, value=bez[0].y) + newKey = fcurve.keyframe_points.insert(frame=bez[0].x, value=bez[0].y, options={'FAST'}) newKey.handle_right = (bez[1].x, bez[1].y) - newKey = fcurve.keyframe_points.insert(frame=bez[3].x, value=bez[3].y) + newKey = fcurve.keyframe_points.insert(frame=bez[3].x, value=bez[3].y, options={'FAST'}) newKey.handle_left = (bez[2].x, bez[2].y) else: for bez in beziers: for vec in bez: vec.resize_2d() - newKey = fcurve.keyframe_points.insert(frame=bez[0].x, value=bez[0].y) + newKey = fcurve.keyframe_points.insert(frame=bez[0].x, value=bez[0].y, options={'FAST'}) newKey.handle_right = (bez[1].x, bez[1].y) - newKey = fcurve.keyframe_points.insert(frame=bez[3].x, value=bez[3].y) + newKey = fcurve.keyframe_points.insert(frame=bez[3].x, value=bez[3].y, options={'FAST'}) newKey.handle_left = (bez[2].x, bez[2].y) + # We used fast remove/insert, time to update the curves! + for fcurve in (curveGroup if group_mode else (curveGroup,)): + fcurve.update() + # indices are detached from data point's frame (x) value and # stored in the dataPoint object, represent a range data_pts = createDataPts(curveGroup, group_mode) + if not data_pts: + return + s = 0 # start e = len(data_pts) - 1 # end @@ -517,6 +521,7 @@ def simplifyCurves(curveGroup, error, reparaError, maxIterations, group_mode): #begin the recursive fitting algorithm. fitCubic(data_pts, s, e) + #remove old Fcurves and insert the new ones createNewCurves(curveGroup, beziers, group_mode) @@ -607,6 +612,8 @@ def denoise(obj, fcurves): Implementation of non-linear blur filter. Finds spikes in the fcurve, and replaces spikes that are too big with the average of the surrounding keyframes. """ + make_editable_fcurves(fcurves) + for fcurve in fcurves: org_pts = fcurve.keyframe_points[:] |