Adverti horiz upsell
Maya 4.0 API Quick Programming Tutorial
Maya 4.0 API Quick Programming Tutorial
admin, updated 2010-07-08 18:49:28 UTC 46,268 views  Rating:
(4 ratings)
Page 4 of 4

Extracting Animation Data


Getting animation information out of Maya involves a little trickery also. Essentially you want to extract information out of the DG at a given time, and then you want to alter the time parameter for each frame. There are several problems. First is how to determine where the keyframes are. Your data will either

  • have been animated in Maya with keyframes carefully set up by your animator for each game frame, in which case you just need to find the time for each keyframe.

  • Or the data has been animated without keyframes, and you only need to evaluate it at a the desired frequency ( e.g. 60 fps ) over the length of the animation.

  • Another way of course is that you will be modeling motion in your game in a way similar to how Maya does it and you just want to extract Maya's own data representations for motion directly ( for example you may just want to grab the motion's actual spline parameters ).

  • I can only help you with the first two ways. The following code will find all the key frames, and the length of an animation:
    void findFrames()
    {
    MItDag dagIter( MItDag::kBreadthFirst, MFn::kInvalid, &stat );
    MTime maxKeyTime = 0;

    for ( ; !dagIter.isDone(); dagIter.next())
    {
    MDagPath dagPath;
    stat = dagIter.getPath( dagPath );

    MFnDagNode dn( dagPath );

    // find all the motion nodes
    MItDependencyGraph dgIter( dagPath.node(),
    MFn::kAnimCurve,
    MItDependencyGraph::kUpstream,
    MItDependencyGraph::kBreadthFirst,
    MItDependencyGraph::kNodeLevel,
    &stat );
    if ( stat )
    {
    // get all the keyframe times
    for ( ; !dgIter.isDone(); dgIter.next())
    {
    MObject anim = dgIter.thisNode( &stat );
    MFnAnimCurve animCurve( anim, &stat );

    // found some keyframe information
    if ( MS::kSuccess == stat )
    {
    u32 numKeys = animCurve.numKeyframes( &stat );
    for ( u32 currKey = 0; currKey < numKeys; currKey++ )
    {
    // Truncating values here...
    MTime keyTime = animCurve.time( currKey, &stat );

    // store this key frame time somewhere.
    storeKeyTime( keyTime );

    // and store the maximum frame time
    if ( time > maxKeyTime )
    maxKeyTime = time;
    }
    }
    }
    }
    }
    }

    maxKeyTime holds the last keyframe time, and the length of an animation. storeKeyTime is a call to your own code to store a given keyframe time so you can evaluate the animation at that time later. Remember that probably many duplicate times will be inserted into that array. There are quite likely many MFnAnimCurve nodes in the DG with the same keyframe times to animate different parts of the model. You can either chose to use the keyframe times as they are stored, or you can chose to use the last maxKeyTime and iterate over fixed steps from 0 to that time. This is something you should probably discuss with those people responsible for making the animations.

    The last part of the problem is how to evaluate a model at a given time, to extract all the vertices, or transforms for a given animation. For this you use the handy MAnimControl object, like so:

    void processAnimationFrame( MTime& time )
    {
    // create a Dag iterator
    MStatus stat;
    MItDag dagIter( MItDag::kBreadthFirst, MFn::kInvalid, &stat );

    // here is the magic animation time setting object. Set it to the
    // desired time, and presto...
    MAnimControl animctrl;
    animctrl.setCurrentTime( time );

    for ( ; !dagIter.isDone(); dagIter.next())
    {
    MDagPath dagPath;
    stat = dagIter.getPath( dagPath );

    if ( stat )
    {
    MFnDagNode dagNode( dagPath, &stat );

    if ( dagNode.isIntermediateObject()) continue;
    if ( !dagPath.hasFn( MFn::kMesh )) continue;
    if ( dagPath.hasFn( MFn::kTransform )) continue;

    // your mesh object... and it should be
    MFnMesh fnMesh( dagPath );

    // get the vertices that are part of the current mesh
    MPointArray vertexList;
    fnMesh.getPoints( vertexList, MSpace::kWorld );

    // iterate through all the vertices
    for ( u32 i = 0; i < vertexList.length(); i++ )
    {
    vertexList[i].cartesianize();
    MPoint point = vertexList[i];

    // here is your data, but this time it should be different
    // for each time at which you evaluate it. You should be
    // able to get tranform information over time in a similar
    // way.
    processVertex( point.x, point.y, point.z );
    }
    }
    }
    }

    And there you have it, everything you need to know to extract basic model information out of Maya.

    Here are some other Maya programming tutorials:

    Highend3d Maya API Tutorials

    Robert Bateman's Maya programming pages

    Michael Comet's Maya programming FAQ