用六种算法实现maya动画曲线光滑

  • Post author:
  • Post category:其他


在使用动补数据的时候,经常会有手脚等部位的抖动,特意写了个command,直接将动画曲线平滑一下,不用动画师大量的进行手调,下面是代码:

smoothAnimationCurveCmd.h

#ifndef _smoothAnimationCurve_
#define _smoothAnimationCurve_

#include <maya/MPxCommand.h>
#include <maya/MObject.h>
#include <maya/MSyntax.h>
#include <maya/MFnAnimCurve.h>
#include <maya/MAnimCurveChange.h>
#include <maya/MItDependencyNodes.h>
#include <maya/MSelectionList.h>
#include <maya/MItSelectionList.h>

class SmoothAnimationCurveCmd: public MPxCommand
{
public:
    SmoothAnimationCurveCmd();
    virtual ~SmoothAnimationCurveCmd();
    virtual MStatus doIt( const MArgList& );
    virtual MStatus redoIt();
    virtual MStatus undoIt();
    virtual bool isUndoable() const { return true; }
    static void *creator(){ return new SmoothAnimationCurveCmd; }
    static MSyntax newSyntax();
    MStatus compliceMethod( MFnAnimCurve &fnAnim, MAnimCurveChange *animCache );
    MItSelectionList getSelectObjectsAnimCurves(); 

private:
    MString type;
    int method;
    unsigned int iterations;
    MAnimCurveChange* pAnimCache;

};

#endif

 

smoothAnimationCurveCmd.cpp

#include "smoothAnimationCurveCmd.h"
#include <maya/MGlobal.h>
#include <maya/MFnPlugin.h>
#include <maya/MDagPath.h>
#include <maya/MPlugArray.h>
#include <maya/MObjectArray.h>
#include <maya/MArgDatabase.h>
#include <maya/MAnimUtil.h>

using namespace std;

const char *typeFlag = "-t", *typeLongFlag = "-type";
const char *methodFlag = "-md", *methodLongFlag = "-method";
const char *iterationsFlag = "-it", *iterationsLongFlag = "-iterations";
const char *helpFlag = "-h", *helpLongFlag = "-help";
const char *helpText = "The smoothAnimCurve command is used to smooth animcurve."
						"\nIt has three parameter."
						"\nFlags:"
						"\n   -h  -help "
						"\n   -it -iterations  Int"
						"\n   -md -method      Int"
						"\n   -t  -type        String"
						"\nSupported Mode:     sel(smooth animation curve only for selected objects)"
						"\n				       all(smooth all animation curves which in the scene)"
						"\nFor quick help use: help smoothAnimCurve";

SmoothAnimationCurveCmd::SmoothAnimationCurveCmd()
{
    type = "all";
    method = 1;
    iterations = 1;
    pAnimCache = NULL;
}

SmoothAnimationCurveCmd::~SmoothAnimationCurveCmd()
{
    delete pAnimCache;
    pAnimCache = NULL;
}

MSyntax SmoothAnimationCurveCmd::newSyntax()
{
    MSyntax syntax;
    syntax.addFlag( typeFlag, typeLongFlag, MSyntax::kString );
    syntax.addFlag( methodFlag, methodLongFlag, MSyntax::kLong );
    syntax.addFlag( iterationsFlag, iterationsLongFlag,  MSyntax::kLong);
	syntax.addFlag( helpFlag, helpLongFlag );
    return syntax;
}

MStatus SmoothAnimationCurveCmd::doIt( const MArgList &args )
{
    MStatus stat;
    unsigned int j;
    MArgDatabase argData( syntax(), args, &stat );
    if( !stat )
        return stat;
    if ( argData.isFlagSet( typeFlag ) )
        argData.getFlagArgument( typeFlag, 0, type );
    if ( argData.isFlagSet( methodFlag ) )
        argData.getFlagArgument( methodFlag, 0, method );
    if ( argData.isFlagSet( iterationsFlag ) )
        argData.getFlagArgument( iterationsFlag, 0, iterations );
	if ( argData.isFlagSet(helpFlag) )
	{
		setResult( helpText );
		return MS::kSuccess;
	}

    pAnimCache = new MAnimCurveChange();
	if(type == "all"){
		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 <= 2)
			{
				continue;
			}
			else
			{
				for (j = 0; j < iterations; j++)
				{
					compliceMethod(fnCurve, pAnimCache);
				}
			}
		}
    }
	if(type == "sel"){
		MObject mAnimCurveObj;
		MItSelectionList animCurveTempIter = getSelectObjectsAnimCurves();
		for(; animCurveTempIter.isDone() != true; animCurveTempIter.next()){

			animCurveTempIter.getDependNode(mAnimCurveObj);
			//cout << mAnimCurveObj.fullPathName() << endl;
			if ( mAnimCurveObj.isNull() )
			{
				continue;
			}
			MFnAnimCurve fnCurve (mAnimCurveObj);
			unsigned int numKeys = fnCurve.numKeys();
			if (numKeys <= 2)
			{
				continue;
			}
			else
			{
				for (j = 0; j < iterations; j++)
				{
					compliceMethod(fnCurve, pAnimCache);
				}
			}
		}
	}

    MGlobal::displayInfo(MString("type: ") + type + " " + MString("method: ") + method + " " + MString("interations: ") + iterations);
    return stat;
}

MItSelectionList SmoothAnimationCurveCmd::getSelectObjectsAnimCurves()
{
    MSelectionList selection;
    MSelectionList animCurvesTemp;
    /*selection.clear();
    animCurvesTemp.clear();*/
    MGlobal::getActiveSelectionList( selection );
    MItSelectionList iter( selection );
    unsigned int j, k;
    for( ; !iter.isDone(); iter.next() )
    {
        MPlugArray mPlugArray;
        MAnimUtil::findAnimatedPlugs( selection, mPlugArray );
        for (j = 0; j < mPlugArray.length(); j++)
        {
            MObjectArray mObjArray;
            MAnimUtil::findAnimation(mPlugArray[j], mObjArray);
            for (k = 0; k < mObjArray.length(); k++ )
            {
                MObject animCurveNode = mObjArray[k];

                if (!animCurveNode.hasFn (MFn::kAnimCurve))
                {
                    continue;
                }
                //MFnAnimCurve animCurve (animCurveNode);
                animCurvesTemp.add( animCurveNode );
                //MGlobal::getSelectionListByName( animCurve.name(),  animCurvesTemp);
            }
        }
    }
	MItSelectionList iterAnimCurvesTemp( animCurvesTemp);
    //MItDependencyNodes iterAnimcurves( iterAnimCurvesTemp, MFn::kAnimCurve );
    return iterAnimCurvesTemp;
}    

MStatus SmoothAnimationCurveCmd::compliceMethod( MFnAnimCurve &fnAnim,  MAnimCurveChange *pAnimCache)
{
    MStatus stat;
    unsigned int i;
    double tempValue;
    unsigned int numKeys = fnAnim.numKeys();
    //pAnimCache = new MAnimCurveChange();
    switch ( method )
    {
    case  0://三点线性
        for (i = 2; i < numKeys - 2; i++)
        {
            tempValue = (fnAnim.value(i - 1) + fnAnim.value(i) + fnAnim.value(i + 1))/3;
            fnAnim.setValue(i, tempValue, pAnimCache);
        }
        break;
    case  1://五点二次滤波
        for (i = 2; i < numKeys - 2; i++)
        {
            tempValue = (12*(fnAnim.value(i - 1) + fnAnim.value(i + 1)) -3*(fnAnim.value(i - 2) + fnAnim.value(i + 2)) + 17*fnAnim.value(i))/35;
            fnAnim.setValue(i, tempValue, pAnimCache);
        }
        break;
    case 2://五点钟形滤波
        for (i = 2; i < numKeys - 2; i++)
        {
            tempValue = (0.11f*(fnAnim.value(i - 2) + fnAnim.value(i + 2)) + 0.24f*(fnAnim.value(i - 1) + fnAnim.value(i + 1)) + 0.3f*fnAnim.value(i));
            fnAnim.setValue(i, tempValue, pAnimCache);
        }
        break;
    case  3://三点汉明滤波
        for (i = 2; i < numKeys - 2; i++)
        {
            tempValue = (0.07f*(fnAnim.value(i - 1)) + 0.86f*(fnAnim.value(i)) + 0.07f*(fnAnim.value(i + 1)));
            fnAnim.setValue(i, tempValue, pAnimCache);
        }
        break;
    case  4://三点钟形滤波
        for (i = 2; i < numKeys - 2; i++)
        {
            tempValue = 0.212f*fnAnim.value(i - 1) + 0.576f*fnAnim.value(i) + 0.212*fnAnim.value(i + 1);
            fnAnim.setValue(i, tempValue, pAnimCache);
        }
        break;
    default://五点汉明滤波
        for (i = 2; i < numKeys - 2; i++)
        {
            tempValue = 0.04f*(fnAnim.value(i - 2) + fnAnim.value(i + 2)) + 0.24f*(fnAnim.value(i - 1) + fnAnim.value(i + 1)) + 0.44f*(fnAnim.value(i));
            fnAnim.setValue(i, tempValue, pAnimCache);
        }
        break;
    }
    return stat;
}

MStatus SmoothAnimationCurveCmd::undoIt()
{
    if( pAnimCache != NULL )
        pAnimCache -> undoIt();
    return MS::kSuccess;
}

MStatus SmoothAnimationCurveCmd::redoIt()
{
    if( pAnimCache != NULL )
        pAnimCache -> redoIt();
    return MS::kSuccess;
}

MStatus initializePlugin( MObject obj )
{
    MFnPlugin plugin( obj, "Lulongfei", "1.0" );
    MStatus stat;
    stat = plugin.registerCommand( "smoothAnimCurve", SmoothAnimationCurveCmd::creator, SmoothAnimationCurveCmd::newSyntax );
    if ( !stat )
        stat.perror( "registerCommand failed" );
    return stat;
}

MStatus uninitializePlugin( MObject obj )
{
    MFnPlugin plugin( obj );
    MStatus stat;
    stat = plugin.deregisterCommand( "smoothAnimCurve" );
    if ( !stat )
        stat.perror( "deregisterCommand failed" );
    return stat;
}

 

使用的时候mel用:smoothAnimCurve -md 0 -t “all” -it 1

python用:cmds.smoothAnimCurve(md = 0, t = “all”, it = 1)

md为使用的方法,从0到5, it为迭代的次数,也就是你想进行几次光滑处理,type是类型,是“all”, 还是“select”。

结果如下:


编译好的插件链接:


https://pan.baidu.com/s/1pCViCZrOhi24ENPvufnSUg



版权声明:本文为lulongfei172006原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。