Simplifying Animation Curves using NURBS Rebuild

This was a bit of a fun exercise, but I’m not sure that it’s actually that practical. Since I’ve been working with a lot of baked animation from mocap data, I wanted a better way to reduce the number of keyframes without impacting the motion too much. One of the things I tried was to make a NURBS curve using the time and value of keyframes as x and y coordinates of the CVs, and then running Maya’s rebuildCurve on that and converting it back into keyframes. It worked to a certain extent, but I ended up getting better results from a different method. But I thought I’d post this anyway in case anyone was interested.

import maya.cmds as mc

def rebuildAnimCurve(tolerance=1):

    #start by getting animation curves from selected objects
    sel = mc.ls(sl=True)
    animCurves = mc.keyframe(sel, query=True, name=True)

    #get the start and end frames
    keyTimes = mc.keyframe(sel, query=True, timeChange=True)
    keyTimes.sort()
    start = keyTimes[0]
    end = keyTimes[-1]

    #bake the curve on ones
    mc.bakeResults(animCurves, sampleBy=1, time=(start,end))

    for each in animCurves:
        #loop through the animation curves.
        #save the time and value as x and y coordinates
        x = mc.keyframe(each,query=True, timeChange=True)
        y = mc.keyframe(each,query=True, valueChange=True)

        points = list()
        numFrames = len(x)

        #put together the points argument for building the curve
        for i in range(numFrames):
            points.append([x[i],y[i],0.0])

        #generate the nurbs curve
        curve = mc.curve(p=points,degree=1)

        #and rebuild it
        mc.rebuildCurve((curve), rebuildType=1, keepEndPoints=False, keepTangents=False, tolerance=tolerance )

        #now cut the keyframes from the object, and create a new animCurve with the points from the NURBS curve.
        mc.cutKey(each,time=(start+1,end-1),clear=True)

        for i in range(mc.getAttr(curve+'.spans')):
            x = mc.pointPosition(curve+'.cv[%i]' % i)[:2]
            mc.setKeyframe(each, time=x[0], value=x[1])

        #delete the curve
        mc.delete(curve)

If you comment or remove that last “mc.delete” line, you’ll be able to see the curves that are generated at the origin. It was fun.

Share Button
This entry was posted in Maya, Python. Bookmark the permalink.

4 Responses to Simplifying Animation Curves using NURBS Rebuild

  1. Jayesh says:

    Hey Morgan this is great tool to optimize any baked animation curves, specially when you want to tweak any motion capture data. I had an experience to clean up mo-cap data manually, when I was a fresher. Your trick for this is working great, I had tested it with different tolerance values, its awesome. I had tried the same thing with different logic which is based on slope formula (http://makwanajayesh.wordpress.com/2012/03/03/mocap-key-optimizar/). It takes 3 keys like P1, P2 and P3 and finds the slope between the line (P1, P3) and (P1, P2) and then it compares the slope values in percentages. If slopes are equal, then P2 is lying between the straight line (P1,P3) ,and it deletes that key. I have given the option for threshold, so user can decide the percentage and accordingly it will deletes the key, even if it is not lying, exactly on a straight line.
    I m still not satisfied with this, because this script is still not working perfectly, specially when, keys values are small like in decimals.

    Thanks for your alternate option…

  2. Hey Jayesh, thanks, I’ll have to check out your script as well. It’s hard to find an automated solution that works exactly how you would do it by hand. What I’d really like to figure out is how to weight the importance of keyframes across all the curves on an object, so that you mostly end up with keys that are on the same frame.

  3. Johnyz says:

    Hey Morgan

    Whats the solution you mentioned worked better?

    J.

  4. You know it’s funny, but I don’t exactly remember. At one point I think I tried something dumb which went through each of the keys, deleted it to see how much the value changed when it was gone, and then put it back if the difference was greater than a certain tolerance. I haven’t worked with motion capture for a while so that stuff sort of fell by the wayside. I’ll see if I can find anything that I may have written.

Leave a Reply

Your email address will not be published. Required fields are marked *