用maya API删除动画曲线多余的关键帧——掐头去尾删帧

来源:互联网 发布:启示录2优化补丁 编辑:程序博客网 时间:2024/05/22 06:55

写这个东西的缘由是一个同事给我说了一个他以前碰到的一个问题:一个文件里有上万条动画曲线,要删除某一帧前面的帧,也要删掉某一帧后面的帧,相当于是掐头去尾,但从功能上来说这个mel完全可以胜任,但是执行起来效率就特别的低,于是他找另一个同事帮他写了个command,这样就将一个6G的含有上万条动画曲线的文件,只用了40多分钟就删完了,最后只剩下1G,而用mel删了一个小时还不到10%,可见二者效率相差。于是自己也想试着写一些,真正写起来没啥难点,主要是两个类,MFnAnimCurve和MAnimCurveChange,同时也实现了redo和undo,实现这个主要是用一个指针在堆中创建一个内存空间,然后将removekey都缓存到这块内存空间里,最后用它自身方法就可以实现redo和undo,自己测试,我这个command效率上没有他的那个夸张,应该是有些地方还不够优化,后面再继续完善吧。想想自己和他们的距离,不,那是天堑,自己还得多加努力啊。具体代码如下:

#include<maya/MPxCommand.h>#include <maya/MFnPlugin.h>#include <maya/MSyntax.h>#include <maya/MDistance.h>#include <maya/MItDependencyNodes.h>#include <maya/MDGModifier.h>#include <maya/MArgDatabase.h>#include <maya/MFnAnimCurve.h>#include <maya/MAnimCurveChange.h>class DeleteKeysCmd : public MPxCommand{public:    DeleteKeysCmd();    ~DeleteKeysCmd();    virtual MStatus doIt( const MArgList& );    virtual MStatus redoIt();    virtual MStatus undoIt();    virtual bool isUndoable() const { return true; };    static void *creator(){ return new DeleteKeysCmd; }    static MSyntax newSyntax();private:    MTime startFrame;    MTime endFrame;    MAnimCurveChange* pAnimCache;};const char *startFrameFlag = "-sf", *startFrameLongFlag = "-startFrame";const char *newendFrameFlag = "-ef", *newendFrameLongFlag = "-endFrame";DeleteKeysCmd::DeleteKeysCmd(){    startFrame.setValue( 0 );    endFrame.setValue( 100 );}DeleteKeysCmd::~DeleteKeysCmd(){    delete pAnimCache;}MSyntax DeleteKeysCmd::newSyntax(){    MSyntax syntax;    syntax.addFlag( startFrameFlag, startFrameLongFlag, MSyntax::kLong );    syntax.addFlag( newendFrameFlag, newendFrameLongFlag, MSyntax::kLong );    return syntax;}MStatus DeleteKeysCmd::doIt( const MArgList &args ){    MStatus stat;    pAnimCache = NULL;    pAnimCache = new MAnimCurveChange();    MArgDatabase argData( syntax(), args, &stat );    if( !stat )        return stat;    if( argData.isFlagSet( startFrameFlag ) )        argData.getFlagArgument( startFrameFlag, 0,  startFrame);    if( argData.isFlagSet( newendFrameLongFlag ) )        argData.getFlagArgument( newendFrameLongFlag, 0,  endFrame);    MDGModifier modifier;    MItDependencyNodes animCurves(MFn::kAnimCurve);        for (; !animCurves.isDone(); animCurves.next())    {        MObject currentItem = animCurves.item();        if ( currentItem.isNull() )        {            continue;        }        MFnAnimCurve fnCurve (currentItem);        unsigned int numKeys = fnCurve.numKeys();        if (numKeys == 0)        {            modifier.deleteNode(currentItem);        }        else        {            unsigned int startFrameIndex = fnCurve.findClosest(startFrame);            for(unsigned int i = 0; i < startFrameIndex; i++)            {                fnCurve.remove(0, pAnimCache);            }            unsigned int endFrameIndex = fnCurve.findClosest(endFrame);            unsigned int numKeysToRemoves = numKeys -1 - endFrameIndex;            for(unsigned int i = 0; i < numKeysToRemoves; i++)            {                fnCurve.remove(endFrameIndex + 1, pAnimCache);            }        }    }    return stat;}MStatus DeleteKeysCmd::undoIt(){    if( pAnimCache != NULL )        pAnimCache -> undoIt();    return MS::kSuccess;}MStatus DeleteKeysCmd::redoIt(){    if( pAnimCache != NULL )        pAnimCache -> redoIt();    return MS::kSuccess;}MStatus initializePlugin( MObject obj ){    MFnPlugin plugin( obj, "Lulongfei", "1.0" );    MStatus stat;    stat = plugin.registerCommand( "deleteKeys", DeleteKeysCmd::creator, DeleteKeysCmd::newSyntax );    if ( !stat )        stat.perror( "registerCommand failed" );    return stat;}MStatus uninitializePlugin( MObject obj ){    MFnPlugin plugin( obj );    MStatus stat;    stat = plugin.deregisterCommand( "deleteKeys" );    if ( !stat )        stat.perror( "deregisterCommand failed" );    return stat;}


下面的是对应的python的api实现方式,相比于mel效率应该也很高,但是相对于C++ Api可能逊色点,也一并放上:

def removeInvalidKeys(start, end):        animCurves = om.MItDependencyNodes(om.MFn.kAnimCurve)        while not animCurves.isDone():            modifier = om.MDGModifier()            fnCurveCache = oma.MAnimCurveChange()            currentItem = animCurves.item()            fnCurve = oma.MFnAnimCurve(currentItem)                if fnCurve.numKeys():                # remove all frame before the start keyframe                startFrameIndex = fnCurve.findClosest(om.MTime(start))                for i in xrange(startFrameIndex):                    fnCurve.remove(0, fnCurveCache)                    # remove all frame after the end keyframe                endFrameIndex = fnCurve.findClosest(om.MTime(end))                for i in xrange(endFrameIndex, fnCurve.numKeys() - 1):                    fnCurve.remove(endFrameIndex + 1, fnCurveCache)                    #fnCurveCache.undoIt()                        else:                modifier.deleteNode(currentItem)                        animCurves.next()

具体使用时cmd可以用:cmds.deleteKeys(sf = 20, ef = 90); mel用deleteKeys -sf 20 -ef 90

而python则直接可以调用function了,removeInvalidKeys(20, 90)

0 0
原创粉丝点击