示例#1
0
int DtCameraGetAnimKeys( int cameraID, MIntArray *keyFrames )
{
    MStatus         status;
    MObject         shapeNode;
    
    MObject         anim;
    MFnDependencyNode dgNode;
    MDagPath        dagPath;
    
    int             currKey,
                    numKeys,
                    keyTime,
                    stat;
                    
                    
    MDagPath        shapeDagPath;
    
    MItDependencyGraph::Direction direction = MItDependencyGraph::kUpstream;
    MItDependencyGraph::Traversal traversalType = MItDependencyGraph::kBreadthFirst;
    MItDependencyGraph::Level level = MItDependencyGraph::kNodeLevel;
    MFn::Type filter = MFn::kAnimCurve;
    
    // A quick check to see if the user has actually given us a valid
    // pointer.
    
    if ( !keyFrames )
    {
        return 0;
    }   
    
    stat = DtExt_CameraGetShapeNode( cameraID, shapeNode );
    if ( 1 != stat )
    {
        cerr << "Problems in cameraGetShapeNode" << endl;
        return 0;
    }   
    
    MItDependencyGraph dgIter( shapeNode, filter, direction,
                            traversalType, level, &status );
                            
    for ( ; !dgIter.isDone(); dgIter.next() )
    {
        anim = dgIter.thisNode( &status );
        MFnAnimCurve animCurve( anim, &status );
        if ( MS::kSuccess == status ) 
        {
            numKeys = animCurve.numKeyframes( &status );
            for ( currKey = 0; currKey < numKeys; currKey++ )
            {
                // Truncating values here; may need more control
                keyTime = (int) animCurve.time( currKey, &status ).value();
                addElement( keyFrames, keyTime );
            }
        }
    }

    return 1;

}
void Exporter::RecursiveJointExtraction(MFnTransform& joint, int parentIndex){

	Bone output;
	output.parent = parentIndex;

	output.invBindPose = joint.transformation().asMatrixInverse().matrix;

	MItDependencyNodes matIt(MFn::kAnimCurve);
	while (!matIt.isDone())
	{
		MFnAnimCurve animCurve(matIt.item());

		if (!strcmp(animCurve.name().substring(0, joint.name().length() - 1).asChar(), joint.name().asChar())){

			cout << animCurve.name().asChar() << endl;
			std::string type = animCurve.name().substring(joint.name().length(), animCurve.name().length()).asChar();
			output.frames.resize(animCurve.time(animCurve.numKeys() - 1).value());
			for (int i = 0; i < output.frames.size(); i++)
			{
				MTime time;
				time.setValue(i);
				output.frames[i].time = time.value();
				if (!strcmp(type.c_str(), "_translateX")){
					cout << animCurve.evaluate(time) << endl;
					output.frames[i].trans.x = animCurve.evaluate(time);
				}
				if (!strcmp(type.c_str(), "_translateY")){
					cout << animCurve.evaluate(time) << endl;
					output.frames[i].trans.y = animCurve.evaluate(time);
				}
				if (!strcmp(type.c_str(), "_translateZ")){
					cout << animCurve.evaluate(time) << endl;
					output.frames[i].trans.z = animCurve.evaluate(time);
				}
				if (!strcmp(type.c_str(), "_rotateX")){
					cout << animCurve.evaluate(time) << endl;
					output.frames[i].rot.x = animCurve.evaluate(time);
				}
				if (!strcmp(type.c_str(), "_rotateY")){
					cout << animCurve.evaluate(time) << endl;
					output.frames[i].rot.y = animCurve.evaluate(time);
				}
				if (!strcmp(type.c_str(), "_rotateZ")){
					cout << animCurve.evaluate(time) << endl;
					output.frames[i].rot.z = animCurve.evaluate(time);
				}
			}
		}
		matIt.next();
	}


	scene_.skeleton.push_back(output);
	int children = joint.childCount();
	int parent = scene_.skeleton.size() - 1;
	for (int i = 0; i < children; i++)
		RecursiveJointExtraction(MFnTransform(joint.child(i)), parent);

};
示例#3
0
bool animWriter::writeAnimCurve(ofstream &clip, 
								const MObject *animCurveObj,
								bool verboseUnits /* false */)
//
//	Description:
//		Write out the anim curve from the clipboard item into the
//		ofstream. The actual anim curve data is written out.
//
//		This method returns true if the write was successful.
//
{
	if (NULL == animCurveObj || animCurveObj->isNull() || !clip) {
		return true;
	}

	MStatus status = MS::kSuccess;
	MFnAnimCurve animCurve(*animCurveObj, &status);
	if (MS::kSuccess != status) {
		cerr << "Error: Could not read the anim curve for export." << endl;
		return false;
	}

	clip << kAnimData << kSpaceChar << kBraceLeftChar << endl;

	clip << kTwoSpace << kInputString << kSpaceChar <<
			boolInputTypeAsWord(animCurve.isUnitlessInput()) << 
			kSemiColonChar << endl;

	clip << kTwoSpace << kOutputString << kSpaceChar <<
			outputTypeAsWord(animCurve.animCurveType()) << kSemiColonChar << endl;

	clip << kTwoSpace << kWeightedString << kSpaceChar <<
			(animCurve.isWeighted() ? 1 : 0) << kSemiColonChar << endl;

	//	These units default to the units in the header of the file.
	//	
	if (verboseUnits) {
		clip << kTwoSpace << kInputUnitString << kSpaceChar;
		if (animCurve.isTimeInput()) {
			MString unitName;
			animUnitNames::setToShortName(timeUnit, unitName);
			clip << unitName;
		} else {
			//	The anim curve has unitless input.
			//
			clip << kUnitlessString;
		}
		clip << kSemiColonChar << endl;

		clip << kTwoSpace << kOutputUnitString << kSpaceChar;
	}

	double conversion = 1.0;
	MString unitName;
	switch (animCurve.animCurveType()) {
		case MFnAnimCurve::kAnimCurveTA:
		case MFnAnimCurve::kAnimCurveUA:
			animUnitNames::setToShortName(angularUnit, unitName);
			if (verboseUnits) clip << unitName;
			{
				MAngle angle(1.0);
				conversion = angle.as(angularUnit);
			}
			break;
		case MFnAnimCurve::kAnimCurveTL:
		case MFnAnimCurve::kAnimCurveUL:
			animUnitNames::setToShortName(linearUnit, unitName);
			if (verboseUnits) clip << unitName;
			{
				MDistance distance(1.0);
				conversion = distance.as(linearUnit);
			}
			break;
		case MFnAnimCurve::kAnimCurveTT:
		case MFnAnimCurve::kAnimCurveUT:
			animUnitNames::setToShortName(timeUnit, unitName);
			if (verboseUnits) clip << unitName;
			break;
		default:
			if (verboseUnits) clip << kUnitlessString;
			break;
	}
	if (verboseUnits) clip << kSemiColonChar << endl;

	if (verboseUnits) {
		MString angleUnitName;
		animUnitNames::setToShortName(angularUnit, angleUnitName);
		clip << kTwoSpace << kTanAngleUnitString << 
				kSpaceChar << angleUnitName << kSemiColonChar << endl;
	}

	clip << kTwoSpace << kPreInfinityString << kSpaceChar <<
			infinityTypeAsWord(animCurve.preInfinityType()) << 
			kSemiColonChar << endl;

	clip << kTwoSpace << kPostInfinityString << kSpaceChar <<
			infinityTypeAsWord(animCurve.postInfinityType()) << 
			kSemiColonChar << endl;

	clip << kTwoSpace << kKeysString << kSpaceChar << kBraceLeftChar << endl;

	// And then write out each keyframe
	//
	unsigned numKeys = animCurve.numKeyframes();
	for (unsigned i = 0; i < numKeys; i++) {
		clip << kTwoSpace << kTwoSpace;
		if (animCurve.isUnitlessInput()) {
			clip << animCurve.unitlessInput(i);
		}
		else {
			clip << animCurve.time(i).value();
		}

		clip << kSpaceChar << (conversion*animCurve.value(i));

		clip << kSpaceChar << tangentTypeAsWord(animCurve.inTangentType(i));
		clip << kSpaceChar << tangentTypeAsWord(animCurve.outTangentType(i));

		clip << kSpaceChar << (animCurve.tangentsLocked(i) ? 1 : 0);
		clip << kSpaceChar << (animCurve.weightsLocked(i) ? 1 : 0);
		clip << kSpaceChar << (animCurve.isBreakdown(i) ? 1 : 0);

		if (animCurve.inTangentType(i) == MFnAnimCurve::kTangentFixed) {
			MAngle angle;
			double weight;
			animCurve.getTangent(i, angle, weight, true);

			clip << kSpaceChar << angle.as(angularUnit);
			clip << kSpaceChar << weight;
		}
		if (animCurve.outTangentType(i) == MFnAnimCurve::kTangentFixed) {
			MAngle angle;
			double weight;
			animCurve.getTangent(i, angle, weight, false);

			clip << kSpaceChar << angle.as(angularUnit);
			clip << kSpaceChar << weight;
		}

		clip << kSemiColonChar << endl;
	}
	clip << kTwoSpace << kBraceRightChar << endl;

	clip << kBraceRightChar << endl;

	return true;
}
//*********************************************************
// Name: processConnections
// Desc: 
//*********************************************************
MStatus BreakdownCommand::processConnections( MPlugArray &connections, unsigned int objID, MString objName )
{
    status = MS::kSuccess;
    bool skipProcessing = false;

    // Under certain conditions, the specified weight must be modified
    double actualBreakdownWeight = breakdownWeight;
    bool isBooleanValue = false;

	for( unsigned int j = 0; j < connections.length(); j++ ) {

        // If the attribute is a boolean or enum, keep its
        // breakdown value the same as its previous key value.
        // Weirdness can occur in things like visibility
        if( isBooleanDataType(connections[j]) || isEnumDataType(connections[j]) )
        {
            // favour the previous key completely
            actualBreakdownWeight = 0.0;
            isBooleanValue = true;
        }
        else {
            actualBreakdownWeight = breakdownWeight;
            isBooleanValue = false;
        }
        
        // When the selectedAttrOnly flag is set, only process
        // attributes that have been selected in the channel box
        if( !selectedAttrOnly || 
            isStrOnSelectedAttrList( connections[j].partialName() ))
        {
		    if( connections[j].isKeyable() && !connections[j].isLocked() ) {

                MPlug currentPlug = connections[j];
			    MItDependencyGraph dgIter( currentPlug,
									       MFn::kAnimCurve,
                                           MItDependencyGraph::kUpstream,
                                           MItDependencyGraph::kBreadthFirst,
                                           MItDependencyGraph::kNodeLevel,
                                           &status );

                for( ; !dgIter.isDone(); dgIter.next() )
                {
                    MObjectArray nodePath;
                    dgIter.getNodePath( nodePath );
 
/*
                    // *** Original solution that didn't support Blend/Charater nodes ***
                    // Only use the anim curves directly connected to the attributes
                    // >1 on a breath first search is level 2.  Root will always be
                    // first in the path
                    if( nodePath.length() > 2 )
                        break;
*/
                    
                    // At a depth of 1 in the DAG, the animation nodes are directly 
                    // connected to animated object.  However, if the depth is greater
                    // than one then we must accomodate both PairBlend nodes and 
                    // Character Set nodes (which sit between the transform node and
                    // the anim nodes.
                    int nodeParentIndex = 1;
                    if( nodePath.length() <= 2 || 
                        (nodePath.length() == 3 && 
                            (nodePath[nodeParentIndex].apiType() == MFn::kPairBlend ||
                            nodePath[nodeParentIndex].apiType() == MFn::kCharacter ))
                        )
                    {

                        MObject anim = dgIter.thisNode( &status );
                        MFnAnimCurve animCurve( anim, &status );

                        // Avoid adding duplicate anim curves to the list
                        // Important when dealing with blend nodes
                        MString curveName = animCurve.name();
                        bool nameExists = false;
                       
                        breakdownList.iterBegin();
                        Breakdown* bkdn = breakdownList.getCurrent();
                        while( bkdn != NULL )
                        {
                            if( bkdn->getAnimCurveFn().name() == curveName ) {
                                nameExists = true;
                                break;
                            }
                            bkdn = breakdownList.getNext();
                        }


                        if( !nameExists )
                        {
                            // Create a breakdown and add it to the list
                            Breakdown* newBreakdown = new Breakdown( animCurve,
                                                                     breakdownWeight,
                                                                     breakdownMode,
                                                                     tickDrawSpecial,
                                                                     currentAnimationFrame,
                                                                     isBooleanValue,
                                                                     objID,
                                                                     &status );
                            // On success, add new breakdown to the list
                            if( status == MS::kSuccess ) {
                                // pluginTrace( "BreakdownCommand", "processConnections", "***Adding Breakdown****" );
                                breakdownList.add( newBreakdown );
                            }

                            // If the breakdown failed, determine how to proceed
                            // from the invalidAttrOp flag
                            else {
                                status = MS::kSuccess;

                                // The command fails if there is an invalid
                                // attribute.  No breakdowns are set.
                                if( invalidAttrOp == kSkipAll ) {
                                    pluginTrace( "BreakdownCommand", "processConnections", "Skipping all objects" );
                                    MGlobal::displayInfo( connections[j].partialName(true) + " --> " + newBreakdown->getErrorMsg());
                                    MGlobal::displayError( "Skipping All Objects (See Script Editor for Invalid Attribute)" );

                                    skipProcessing = true;
                                    status = MS::kFailure;

                                    break;
                                }

                                // The object is skipped.  All breakdowns already
                                // added for attributes on this object will need
                                // to be removed from the list
                                else if( invalidAttrOp == kSkipObject ) {
                                    pluginTrace( "BreakdownCommand", "processConnections", "Skipping object: " + objName );
                                    MGlobal::displayInfo( "Skipping Object: " + objName );
                                
                                    breakdownList.deleteBreakdowns( objID );
                                    skipProcessing = true;
                                    objectsSkipped = true;

                                    break;
                                }

                                // If only invalid attributes are to be skipped
                                // just delete the breakdown and carry on
                                else if( invalidAttrOp == kSkipAttr ) {
                                    pluginTrace( "BreakdownCommand", "processConnections", "Skipping attribute: " + connections[j].partialName( true ));
                                    MGlobal::displayInfo( "Skipping Attribute: " +
                                                              connections[j].partialName( true ) +
                                                              " (" + newBreakdown->getErrorMsg() + ")" );
                                    attributesSkipped = true;
                                }

                                // Clean up memory for discarded breakdowns
                                delete newBreakdown;
                            }
                        }
                    }
                }
            }
        }
        // Don't keep processing connections if the object
        // should be skipped (invalid attribute flag)
        if( skipProcessing )
            break;

	}

    return status;
}
// In order for the new animation curve positions to match the controller's previous global position,
// first we need to get the controller's global transform matrix. The new local position of the controller
// will be the controller's global transform matrix multiplied by the inverse of the new parent group's
// global transform matrix.
// So if:
//  [A] = controller's global transformation matrix
//  [B] = parent group's global transformation matrix
//  [X] = controller's new local transformation matrix
// Then:
//  [X] = [A]inverse([B])
//
// The controller's new local transformation matrix needs to be calculated per keyframe, which is why
// a map of world position matrices for the controller are passed in as a parameter. The key for the map
// is the time at which the associated world matrix was stored.
MStatus lrutils::updateAnimCurves(MObject transformObj, std::map<double, MMatrix> ctlWorldMatrices, MMatrix ctlGroupMatrix) {
    MStatus status = MS::kFailure;
    MFnTransform transformFn( transformObj, &status );
    MyCheckStatusReturn(status, status.errorString() );

    //get all of the connections from the transform node
    MPlugArray transformConnections;
    status = transformFn.getConnections( transformConnections );
    MyCheckStatusReturn(status, status.errorString() );
    for(unsigned int i = 0; i < transformConnections.length(); i++) {
        //get all of the plugs this plug is connected to as a destination
        MPlugArray connectedPlugs;
        transformConnections[i].connectedTo(connectedPlugs,true,false,&status);
        MyCheckStatusReturn(status, status.errorString() );
        MString plugName = transformConnections[i].partialName(false,false,false,false,false,true);
        for(unsigned int j = 0; j < connectedPlugs.length(); j++) {
            MObject connectedObj = connectedPlugs[j].node();
            MFn::Type animType = connectedObj.apiType();
            //if the connected object is an animCurveT[L,A], then transform it
            if( (animType == MFn::kAnimCurveTimeToDistance) || (animType == MFn::kAnimCurveTimeToAngular) ) {
                MFnAnimCurve animCurve(connectedObj, &status);
                MyCheckStatusReturn(status, status.errorString() );
                //iterate through every key in the curve
                for(unsigned int k = 0; k < animCurve.numKeys(); k++) {
                    double keyTime = animCurve.time(k, &status).value();
                    MyCheckStatusReturn( status, status.errorString() );
                    double keyVal = animCurve.value(k, &status);
                    MyCheckStatusReturn( status, status.errorString() );

                    float tangentX, tangentY;
                    status = animCurve.getTangent(k, tangentX, tangentY, false);
                    MyCheckStatusReturn(status, status.errorString() );
                    //stringstream tmp;
                    //tmp << "out tangent = (" << tangentX << "," << tangentY << ")";
                    //MGlobal::displayInfo(tmp.str().c_str());

                    //calculate the controller's local transformation matrix
                    //first retrieve the corresponding world matrix for this key time
                    MMatrix ctlWorldMatrix = ctlWorldMatrices[keyTime];
                        //if the transformation matrices are the same, don't update the curve
                    //if( ctlWorldMatrix == ctlGroupMatrix) {
                    //    continue;
                    //}
                    MTransformationMatrix ctlGroupTransMatrix(ctlGroupMatrix);
                    MMatrix ctlGroupMatrixInverse = ctlGroupTransMatrix.asMatrixInverse();
                    MMatrix newCtlLocalMatrix = ctlWorldMatrix * ctlGroupMatrixInverse;
                    MTransformationMatrix newCtlLocalTransMatrix(newCtlLocalMatrix);

                    //determine if the curve is for translation data
                    if(animType == MFn::kAnimCurveTimeToDistance) {
                        MVector vTransform = newCtlLocalTransMatrix.translation(MSpace::kTransform);
                        if( plugName.indexW( MString("X") ) != -1 ) {
                            keyVal = vTransform.x;
                        } else if ( plugName.indexW( MString("Y") ) != -1 ) {
                            keyVal = vTransform.y;
                        } else if ( plugName.indexW( MString("Z") ) != -1 ) {
                            keyVal = vTransform.z;
                        }
                    //if the curve is for rotation data
                    } else if (animType == MFn::kAnimCurveTimeToAngular) {
                        double* rotation = new double[3];
                        MTransformationMatrix::RotationOrder rotOrder = MTransformationMatrix::kXYZ;
                        newCtlLocalTransMatrix.getRotation(rotation,rotOrder);
                        if( plugName.indexW( MString("X") ) != -1 ) {
                            keyVal = rotation[0];
                        } else if ( plugName.indexW( MString("Y") ) != -1 ) {
                            keyVal = rotation[1];
                        } else if ( plugName.indexW( MString("Z") ) != -1 ) {
                            keyVal = rotation[2];
                        }                        
                    }
                    animCurve.setValue(k, keyVal);
                    status = MS::kSuccess;
                }
            }
        }
    }
    return status;
}