当前位置:   article > 正文

用maya API删除动画曲线多余的关键帧——掐头去尾删帧_maya自动删除中间过度关键帧

maya自动删除中间过度关键帧

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

  1. #include<maya/MPxCommand.h>
  2. #include <maya/MFnPlugin.h>
  3. #include <maya/MSyntax.h>
  4. #include <maya/MDistance.h>
  5. #include <maya/MItDependencyNodes.h>
  6. #include <maya/MDGModifier.h>
  7. #include <maya/MArgDatabase.h>
  8. #include <maya/MFnAnimCurve.h>
  9. #include <maya/MAnimCurveChange.h>
  10. class DeleteKeysCmd : public MPxCommand
  11. {
  12. public:
  13. DeleteKeysCmd();
  14. ~DeleteKeysCmd();
  15. virtual MStatus doIt( const MArgList& );
  16. virtual MStatus redoIt();
  17. virtual MStatus undoIt();
  18. virtual bool isUndoable() const { return true; };
  19. static void *creator(){ return new DeleteKeysCmd; }
  20. static MSyntax newSyntax();
  21. private:
  22. MTime startFrame;
  23. MTime endFrame;
  24. MAnimCurveChange* pAnimCache;
  25. };
  26. const char *startFrameFlag = "-sf", *startFrameLongFlag = "-startFrame";
  27. const char *newendFrameFlag = "-ef", *newendFrameLongFlag = "-endFrame";
  28. DeleteKeysCmd::DeleteKeysCmd()
  29. {
  30. startFrame.setValue( 0 );
  31. endFrame.setValue( 100 );
  32. }
  33. DeleteKeysCmd::~DeleteKeysCmd()
  34. {
  35. delete pAnimCache;
  36. }
  37. MSyntax DeleteKeysCmd::newSyntax()
  38. {
  39. MSyntax syntax;
  40. syntax.addFlag( startFrameFlag, startFrameLongFlag, MSyntax::kLong );
  41. syntax.addFlag( newendFrameFlag, newendFrameLongFlag, MSyntax::kLong );
  42. return syntax;
  43. }
  44. MStatus DeleteKeysCmd::doIt( const MArgList &args )
  45. {
  46. MStatus stat;
  47. pAnimCache = NULL;
  48. pAnimCache = new MAnimCurveChange();
  49. MArgDatabase argData( syntax(), args, &stat );
  50. if( !stat )
  51. return stat;
  52. if( argData.isFlagSet( startFrameFlag ) )
  53. argData.getFlagArgument( startFrameFlag, 0, startFrame);
  54. if( argData.isFlagSet( newendFrameLongFlag ) )
  55. argData.getFlagArgument( newendFrameLongFlag, 0, endFrame);
  56. MDGModifier modifier;
  57. MItDependencyNodes animCurves(MFn::kAnimCurve);
  58. for (; !animCurves.isDone(); animCurves.next())
  59. {
  60. MObject currentItem = animCurves.item();
  61. if ( currentItem.isNull() )
  62. {
  63. continue;
  64. }
  65. MFnAnimCurve fnCurve (currentItem);
  66. unsigned int numKeys = fnCurve.numKeys();
  67. if (numKeys == 0)
  68. {
  69. modifier.deleteNode(currentItem);
  70. }
  71. else
  72. {
  73. unsigned int startFrameIndex = fnCurve.findClosest(startFrame);
  74. for(unsigned int i = 0; i < startFrameIndex; i++)
  75. {
  76. fnCurve.remove(0, pAnimCache);
  77. }
  78. unsigned int endFrameIndex = fnCurve.findClosest(endFrame);
  79. unsigned int numKeysToRemoves = numKeys -1 - endFrameIndex;
  80. for(unsigned int i = 0; i < numKeysToRemoves; i++)
  81. {
  82. fnCurve.remove(endFrameIndex + 1, pAnimCache);
  83. }
  84. }
  85. }
  86. return stat;
  87. }
  88. MStatus DeleteKeysCmd::undoIt()
  89. {
  90. if( pAnimCache != NULL )
  91. pAnimCache -> undoIt();
  92. return MS::kSuccess;
  93. }
  94. MStatus DeleteKeysCmd::redoIt()
  95. {
  96. if( pAnimCache != NULL )
  97. pAnimCache -> redoIt();
  98. return MS::kSuccess;
  99. }
  100. MStatus initializePlugin( MObject obj )
  101. {
  102. MFnPlugin plugin( obj, "Lulongfei", "1.0" );
  103. MStatus stat;
  104. stat = plugin.registerCommand( "deleteKeys", DeleteKeysCmd::creator, DeleteKeysCmd::newSyntax );
  105. if ( !stat )
  106. stat.perror( "registerCommand failed" );
  107. return stat;
  108. }
  109. MStatus uninitializePlugin( MObject obj )
  110. {
  111. MFnPlugin plugin( obj );
  112. MStatus stat;
  113. stat = plugin.deregisterCommand( "deleteKeys" );
  114. if ( !stat )
  115. stat.perror( "deregisterCommand failed" );
  116. return stat;
  117. }


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

  1. def removeInvalidKeys(start, end):
  2. animCurves = om.MItDependencyNodes(om.MFn.kAnimCurve)
  3. while not animCurves.isDone():
  4. modifier = om.MDGModifier()
  5. fnCurveCache = oma.MAnimCurveChange()
  6. currentItem = animCurves.item()
  7. fnCurve = oma.MFnAnimCurve(currentItem)
  8. if fnCurve.numKeys():
  9. # remove all frame before the start keyframe
  10. startFrameIndex = fnCurve.findClosest(om.MTime(start))
  11. for i in xrange(startFrameIndex):
  12. fnCurve.remove(0, fnCurveCache)
  13. # remove all frame after the end keyframe
  14. endFrameIndex = fnCurve.findClosest(om.MTime(end))
  15. for i in xrange(endFrameIndex, fnCurve.numKeys() - 1):
  16. fnCurve.remove(endFrameIndex + 1, fnCurveCache)
  17. #fnCurveCache.undoIt()
  18. else:
  19. modifier.deleteNode(currentItem)
  20. animCurves.next()

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

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

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号