MStatus lrutils::getMetaChildByName(MObject metaNodeObj, MString name, MObject& metaChildObj) { MStatus status = MS::kFailure; MFnDependencyNode metaNodeFn( metaNodeObj ); MPlug metaChildrenPlug = metaNodeFn.findPlug( "metaChildren", true, &status ); MyCheckStatusReturn(status, "MFnDependencyNode.findPlug() failed"); //follow the plug connection to the connected plug on the other object MPlugArray connectedChildPlugs; metaChildrenPlug.connectedTo(connectedChildPlugs,false,true,&status); MyCheckStatusReturn(status,"MPlug.connectedTo() failed"); for (unsigned int i = 0; i < connectedChildPlugs.length(); i++) { MPlug connectedPlug = connectedChildPlugs[i]; MObject connectedNodeObj = connectedPlug.node(&status); MyCheckStatusReturn(status, "MPlug.node() failed"); MFnDependencyNode connectedNodeFn( connectedNodeObj ); MString connectedNodeName = connectedNodeFn.name(); int index = connectedNodeName.indexW( name ); if( index != -1 ) { metaChildObj = connectedNodeObj; status = MS::kSuccess; break; } } return status; }
MStatus lrutils::getMetaChildByRigId(MObject metaNodeObj, MString rigId, MObject& metaChildObj) { MStatus status = MS::kFailure; MFnDependencyNode metaNodeFn( metaNodeObj ); MPlug metaChildrenPlug = metaNodeFn.findPlug( "metaChildren", true, &status ); MyCheckStatusReturn(status, "MFnDependencyNode.findPlug() failed"); //follow the plug connection to the connected plug on the other object MPlugArray connectedChildPlugs; metaChildrenPlug.connectedTo(connectedChildPlugs,false,true,&status); MyCheckStatusReturn(status,"MPlug.connectedTo() failed"); for (unsigned int i = 0; i < connectedChildPlugs.length(); i++) { MPlug connectedPlug = connectedChildPlugs[i]; MObject connectedNodeObj = connectedPlug.node(&status); MyCheckStatusReturn(status, "MPlug.node() failed"); MFnDependencyNode connectedNodeFn( connectedNodeObj ); //get the rigId number held in the rigId attribute MPlug rigIdPlug = connectedNodeFn.findPlug(MString("rigId"),true,&status); MyCheckStatusReturn(status,"findPlug failed"); MString childRigId; rigIdPlug.getValue(childRigId); //if rigId is in childRigId then return the object if( childRigId.indexW(rigId) != -1 ) { metaChildObj = connectedNodeObj; status = MS::kSuccess; break; } } return status; }
MStatus lrutils::stringReplaceAll(MString &source, MString search, MString replace) { MStatus status = MS::kFailure; //part of the string that has already been searched MString sourceProcessed; //part of the string that has not been searched yet MString sourceUnprocessed = source; int index = 0; int index2 = 0; //if the search and replace strings are the same, don't bother to change the string if( search == replace ) return MS::kSuccess; for(;;) { index = sourceUnprocessed.indexW( search ); if (index == -1 || sourceUnprocessed.numChars() == 0) { //if the search string is not found, end and add the rest of the string to //the part already processed sourceProcessed += sourceUnprocessed; break; } MString subString1 = source.substringW(0,index-1); index2 = index + search.numChars(); MString subString2; if (index2 < (int)(source.numChars() - 1) ) { subString2 = source.substringW(index2,source.numChars()-1); } sourceProcessed += subString1 + replace; sourceUnprocessed = subString2; status = MS::kSuccess; } source = sourceProcessed; 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; }