// Populate the AnimationChannel vector with various ops based on the Maya // transformation logic If scale and/or rotate pivot are declared, create // inverse ops in the appropriate order void MayaTransformWriter::pushTransformStack( const MFnTransform& iTrans, const UsdGeomXformable& usdXformable, bool writeAnim) { // NOTE: I think this logic and the logic in MayaTransformReader // should be merged so the concept of "CommonAPI" stays centralized. // // By default we assume that the xform conforms to the common API // (xlate,pivot,rotate,scale,pivotINVERTED) As soon as we encounter any // additional xform (compensation translates for pivots, rotateAxis or // shear) we are not conforming anymore bool conformsToCommonAPI = true; // Keep track of where we have rotate and scale Pivots and their inverse so // that we can combine them later if possible unsigned int rotPivotIdx = -1, rotPivotINVIdx = -1, scalePivotIdx = -1, scalePivotINVIdx = -1; // Check if the Maya prim inheritTransform MPlug inheritPlug = iTrans.findPlug("inheritsTransform"); if (!inheritPlug.isNull()) { if(!inheritPlug.asBool()) { usdXformable.SetResetXformStack(true); } } // inspect the translate, no suffix to be closer compatibility with common API _GatherAnimChannel(TRANSLATE, iTrans, "translate", "X", "Y", "Z", &mAnimChanList, writeAnim, false); // inspect the rotate pivot translate if (_GatherAnimChannel(TRANSLATE, iTrans, "rotatePivotTranslate", "X", "Y", "Z", &mAnimChanList, writeAnim, true)) { conformsToCommonAPI = false; } // inspect the rotate pivot bool hasRotatePivot = _GatherAnimChannel(TRANSLATE, iTrans, "rotatePivot", "X", "Y", "Z", &mAnimChanList, writeAnim, true); if (hasRotatePivot) { rotPivotIdx = mAnimChanList.size()-1; } // inspect the rotate, no suffix to be closer compatibility with common API _GatherAnimChannel(ROTATE, iTrans, "rotate", "X", "Y", "Z", &mAnimChanList, writeAnim, false); // inspect the rotateAxis/orientation if (_GatherAnimChannel(ROTATE, iTrans, "rotateAxis", "X", "Y", "Z", &mAnimChanList, writeAnim, true)) { conformsToCommonAPI = false; } // invert the rotate pivot if (hasRotatePivot) { AnimChannel chan; chan.usdOpType = UsdGeomXformOp::TypeTranslate; chan.precision = UsdGeomXformOp::PrecisionFloat; chan.opName = "rotatePivot"; chan.isInverse = true; mAnimChanList.push_back(chan); rotPivotINVIdx = mAnimChanList.size()-1; } // inspect the scale pivot translation if (_GatherAnimChannel(TRANSLATE, iTrans, "scalePivotTranslate", "X", "Y", "Z", &mAnimChanList, writeAnim, true)) { conformsToCommonAPI = false; } // inspect the scale pivot point bool hasScalePivot = _GatherAnimChannel(TRANSLATE, iTrans, "scalePivot", "X", "Y", "Z", &mAnimChanList, writeAnim, true); if (hasScalePivot) { scalePivotIdx = mAnimChanList.size()-1; } // inspect the shear. Even if we have one xform on the xform list, it represents a share so we should name it if (_GatherAnimChannel(SHEAR, iTrans, "shear", "XY", "XZ", "YZ", &mAnimChanList, writeAnim, true)) { conformsToCommonAPI = false; } // add the scale. no suffix to be closer compatibility with common API _GatherAnimChannel(SCALE, iTrans, "scale", "X", "Y", "Z", &mAnimChanList, writeAnim, false); // inverse the scale pivot point if (hasScalePivot) { AnimChannel chan; chan.usdOpType = UsdGeomXformOp::TypeTranslate; chan.precision = UsdGeomXformOp::PrecisionFloat; chan.opName = "scalePivot"; chan.isInverse = true; mAnimChanList.push_back(chan); scalePivotINVIdx = mAnimChanList.size()-1; } // If still potential common API, check if the pivots are the same and NOT animated/connected if (hasRotatePivot != hasScalePivot) { conformsToCommonAPI = false; } if (conformsToCommonAPI && hasRotatePivot && hasScalePivot) { AnimChannel rotPivChan, scalePivChan; rotPivChan = mAnimChanList[rotPivotIdx]; scalePivChan = mAnimChanList[scalePivotIdx]; // If they have different sampleType or are ANIMATED, does not conformsToCommonAPI anymore for (unsigned int i = 0;i<3;i++) { if (rotPivChan.sampleType[i] != scalePivChan.sampleType[i] || rotPivChan.sampleType[i] == ANIMATED) { conformsToCommonAPI = false; } } // If The defaultValue is not the same, does not conformsToCommonAPI anymore if (!GfIsClose(rotPivChan.defValue, scalePivChan.defValue, 1e-9)) { conformsToCommonAPI = false; } // If opType, usdType or precision are not the same, does not conformsToCommonAPI anymore if (rotPivChan.opType != scalePivChan.opType || rotPivChan.usdOpType != scalePivChan.usdOpType || rotPivChan.precision != scalePivChan.precision) { conformsToCommonAPI = false; } if (conformsToCommonAPI) { // To Merge, we first rename rotatePivot and the scalePivot inverse // to pivot. Then we remove the scalePivot and the inverse of the // rotatePivot. // // This means that pivot and its inverse will wrap rotate and scale // since no other ops have been found // // NOTE: scalePivotIdx > rotPivotINVIdx mAnimChanList[rotPivotIdx].opName = "pivot"; mAnimChanList[scalePivotINVIdx].opName = "pivot"; mAnimChanList.erase(mAnimChanList.begin()+scalePivotIdx); mAnimChanList.erase(mAnimChanList.begin()+rotPivotINVIdx); } } // Loop over anim channel vector and create corresponding XFormOps // including the inverse ones if needed TF_FOR_ALL(iter, mAnimChanList) { AnimChannel& animChan = *iter; animChan.op = usdXformable.AddXformOp( animChan.usdOpType, animChan.precision, TfToken(animChan.opName), animChan.isInverse); }
MStatus simulateBoids::doIt( const MArgList& args ) { // Description: implements the MEL boids command // Arguments: args - the argument list that was passes to the command from MEL MStatus status = MS::kSuccess; /**************************************** * building thread/dll data structure * ****************************************/ InfoCache infoCache; SimulationParameters simParams; RulesParameters *applyingRules; double progressBar=0; double aov=pi/3; int i,numberOfDesires=0; // params retrievement MSelectionList sel; MObject node; MFnDependencyNode nodeFn; MFnTransform locatorFn; MPlug plug; // simulation params int simulationLengthValue; // [int] in seconds int framesPerSecondValue; // [int] int startFrameValue; // [int] int boidsNumberValue; // [int] // export params MString logFilePathValue; // [char *] MString logFileNameValue; // [char *] int logFileTypeValue; // 0 = nCache; 1 = log file; 2 = XML; // locomotion params int locomotionModeValue; // [int] double maxSpeedValue; // [double] double maxForceValue; // [double] // double mass=1; // [double] MTime currentTime, maxTime; MPlug plugX, plugY, plugZ; double tx, ty, tz; int frameLength ; Vector * leader = NULL; MStatus leaderFound=MStatus::kFailure; MGlobal::getActiveSelectionList(sel); for ( MItSelectionList listIter(sel); !listIter.isDone(); listIter.next() ) { listIter.getDependNode(node); switch(node.apiType()) { case MFn::kTransform: // get locator transform to follow leaderFound=locatorFn.setObject(node); cout << locatorFn.name().asChar() << " is selected as locator" << endl; break; case MFn::kPluginDependNode: nodeFn.setObject(node); cout << nodeFn.name().asChar() << " is selected as brain" << endl; break; default: break; } cout<< node.apiTypeStr()<<endl; } // rules params setRuleVariables(alignment); setRuleVariables(cohesion); setRuleVariables(separation); setRuleVariables(follow); getPlugValue(simulationLength); getPlugValue(framesPerSecond); getPlugValue(startFrame); getPlugValue(boidsNumber); getPlugValue(logFileType); getRulePlugValue(alignment); getRulePlugValue(cohesion); getRulePlugValue(separation); getRulePlugValue(follow); getPlugValue(locomotionMode); getPlugValue(maxSpeed); getPlugValue(maxForce); getTypePlugValue(logFilePath); getTypePlugValue(logFileName); // counting active rules number if(alignmentActiveValue) numberOfDesires++; if(cohesionActiveValue) numberOfDesires++; if(separationActiveValue) numberOfDesires++; if(followActiveValue) numberOfDesires++; currentTime = MTime((double)startFrameValue); // MAnimControl::minTime(); maxTime = MTime((double)(startFrameValue + (simulationLengthValue * framesPerSecondValue))); // MAnimControl::maxTime(); cout << "time unit enum (6 is 24 fps): " << currentTime.unit() << endl; plugX = locatorFn.findPlug( MString( "translateX" ), &status ); plugY = locatorFn.findPlug( MString( "translateY" ), &status ); plugZ = locatorFn.findPlug( MString( "translateZ" ), &status ); frameLength = simulationLengthValue * framesPerSecondValue; if(leaderFound==MS::kSuccess) { leader = new Vector[frameLength]; while ( currentTime < maxTime ) { { int index = (int)currentTime.value() - startFrameValue; /* MGlobal::viewFrame(currentTime); pos = locatorFn.getTranslation(MSpace::kWorld); cout << "pos: " << pos.x << " " << pos.y << " " << pos.z << endl; */ status = plugX.getValue( tx, MDGContext(currentTime) ); status = plugY.getValue( ty, MDGContext(currentTime) ); status = plugZ.getValue( tz, MDGContext(currentTime) ); leader[index].x = tx; leader[index].y = ty; leader[index].z = tz; //cout << "pos at time " << currentTime.value() << " has x: " << tx << " y: " << ty << " z: " << tz << endl; currentTime++; } } } simParams.fps=framesPerSecondValue; simParams.lenght=simulationLengthValue; simParams.numberOfBoids=boidsNumberValue; simParams.maxAcceleration=maxForceValue; simParams.maxVelocity=maxSpeedValue; simParams.simplifiedLocomotion=TRUE; applyingRules=new RulesParameters[numberOfDesires]; // cache settings MString saveString; saveString = logFilePathValue+"/"+logFileNameValue; infoCache.fileName=new char[saveString.length()+1]; memcpy(infoCache.fileName,saveString.asChar(),sizeof(char)*(saveString.length()+1)); infoCache.cacheFormat=ONEFILE; infoCache.fps=framesPerSecondValue; infoCache.start=startFrameValue/framesPerSecondValue; infoCache.end=simulationLengthValue+infoCache.start; infoCache.loging=FALSE; infoCache.option=POSITIONVELOCITY; infoCache.particleSysName="BoidsNParticles"; infoCache.saveMethod=MAYANCACHE; for(i=0;i<numberOfDesires;i++) { applyingRules[i].enabled=TRUE; applyingRules[i].precedence=1; applyingRules[i].aov=aov; applyingRules[i].visibilityOption=FALSE; } if(cohesionActiveValue==0) applyingRules[COHESIONRULE].enabled=FALSE; else { applyingRules[COHESIONRULE].ruleName=COHESIONRULE; applyingRules[COHESIONRULE].ruleFactor=cohesionFactorValue; applyingRules[COHESIONRULE].ruleRadius=cohesionRadiusValue; applyingRules[COHESIONRULE].ruleWeight=cohesionWeightValue; } if(separationActiveValue==0) applyingRules[SEPARATIONRULE].enabled=FALSE; else { applyingRules[SEPARATIONRULE].ruleName=SEPARATIONRULE; applyingRules[SEPARATIONRULE].ruleFactor=separationFactorValue; applyingRules[SEPARATIONRULE].ruleRadius=separationRadiusValue; applyingRules[SEPARATIONRULE].ruleWeight=separationWeightValue; } if(alignmentActiveValue==0) applyingRules[ALIGNMENTRULE].enabled=FALSE; else { applyingRules[ALIGNMENTRULE].ruleName=ALIGNMENTRULE; applyingRules[ALIGNMENTRULE].ruleFactor=alignmentFactorValue; applyingRules[ALIGNMENTRULE].ruleRadius=alignmentRadiusValue; applyingRules[ALIGNMENTRULE].ruleWeight=alignmentWeightValue; } if(followActiveValue==0) applyingRules[FOLLOWRULE].enabled=FALSE; else { applyingRules[FOLLOWRULE].ruleName=FOLLOWRULE; applyingRules[FOLLOWRULE].ruleRadius=followRadiusValue; applyingRules[FOLLOWRULE].ruleFactor=followFactorValue; applyingRules[FOLLOWRULE].ruleWeight=followWeightValue; } // initializing simulation parameters boidInit(numberOfDesires, applyingRules, simParams , infoCache, leader); DLLData datadll; // preparing threads pool status = MThreadPool::init(); if (status==MStatus::kSuccess) { MThreadPool::newParallelRegion(ThreadsCreator, &datadll); setResult( "Command executed!\n" ); CHECK_MSTATUS(MProgressWindow::endProgress()); MThreadPool::release(); } switch(datadll.result) { case 0: status=MS::kSuccess; break; default: status=MS::kFailure; } MThreadPool::release(); return status; }
// Creates an AnimChannel from a Maya compound attribute if there is meaningful // data. This means we found data that is non-identity. // // returns true if we extracted an AnimChannel and false otherwise (e.g., the // data was identity). static bool _GatherAnimChannel( XFormOpType opType, const MFnTransform& iTrans, MString parentName, MString xName, MString yName, MString zName, std::vector<AnimChannel>* oAnimChanList, bool isWritingAnimation, bool setOpName) { AnimChannel chan; chan.opType = opType; chan.isInverse = false; if (setOpName) { chan.opName = parentName.asChar(); } // We default to single precision (later we set the main translate op and // shear to double) chan.precision = UsdGeomXformOp::PrecisionFloat; unsigned int validComponents = 0; // this is to handle the case where there is a connection to the parent // plug but not to the child plugs, if the connection is there and you are // not forcing static, then all of the children are considered animated int parentSample = PxrUsdMayaUtil::getSampledType(iTrans.findPlug(parentName),false); // Determine what plug are needed based on default value & being // connected/animated MStringArray channels; channels.append(parentName+xName); channels.append(parentName+yName); channels.append(parentName+zName); GfVec3d nullValue(opType == SCALE ? 1.0 : 0.0); for (unsigned int i = 0; i<3; i++) { // Find the plug and retrieve the data as the channel default value. It // won't be updated if the channel is NOT ANIMATED chan.plug[i] = iTrans.findPlug(channels[i]); double plugValue = chan.plug[i].asDouble(); chan.defValue[i] = opType == ROTATE ? GfRadiansToDegrees(plugValue) : plugValue; chan.sampleType[i] = NO_XFORM; // If we allow animation and either the parentsample or local sample is // not 0 then we havea ANIMATED sample else we have a scale and the // value is NOT 1 or if the value is NOT 0 then we have a static xform if ((parentSample != 0 || PxrUsdMayaUtil::getSampledType(chan.plug[i], true) != 0) && isWritingAnimation) { chan.sampleType[i] = ANIMATED; validComponents++; } else if (!GfIsClose(chan.defValue[i], nullValue[i], 1e-7)) { chan.sampleType[i] = STATIC; validComponents++; } } // If there are valid component, then we will add the animation channel. // Rotates with 1 component will be optimized to single axis rotation if (validComponents>0) { if (opType == SCALE) { chan.usdOpType = UsdGeomXformOp::TypeScale; } else if (opType == TRANSLATE) { chan.usdOpType = UsdGeomXformOp::TypeTranslate; // The main translate is set to double precision if (parentName == "translate") { chan.precision = UsdGeomXformOp::PrecisionDouble; } } else if (opType == ROTATE) { chan.usdOpType = UsdGeomXformOp::TypeRotateXYZ; if (validComponents == 1) { if (chan.sampleType[0] != NO_XFORM) chan.usdOpType = UsdGeomXformOp::TypeRotateX; if (chan.sampleType[1] != NO_XFORM) chan.usdOpType = UsdGeomXformOp::TypeRotateY; if (chan.sampleType[2] != NO_XFORM) chan.usdOpType = UsdGeomXformOp::TypeRotateZ; } else { // Rotation Order ONLY applies to the "rotate" attribute if (parentName == "rotate") { switch (iTrans.rotationOrder()) { case MTransformationMatrix::kYZX: chan.usdOpType = UsdGeomXformOp::TypeRotateYZX; break; case MTransformationMatrix::kZXY: chan.usdOpType = UsdGeomXformOp::TypeRotateZXY; break; case MTransformationMatrix::kXZY: chan.usdOpType = UsdGeomXformOp::TypeRotateXZY; break; case MTransformationMatrix::kYXZ: chan.usdOpType = UsdGeomXformOp::TypeRotateYXZ; break; case MTransformationMatrix::kZYX: chan.usdOpType = UsdGeomXformOp::TypeRotateZYX; break; default: break; } } } } else if (opType == SHEAR) { chan.usdOpType = UsdGeomXformOp::TypeTransform; chan.precision = UsdGeomXformOp::PrecisionDouble; } else { return false; } oAnimChanList->push_back(chan); return true; } return false; }
/******************************************************************************************************** * Method to translate a single camera * ********************************************************************************************************/ MStatus OgreExporter::writeCamera(MFnCamera& camera) { MPlug plug; MPlugArray srcplugarray; double dist; MAngle angle; MFnTransform* cameraTransform = NULL; MFnAnimCurve* animCurve = NULL; // get camera transform for (int i=0; i<camera.parentCount(); i++) { if (camera.parent(i).hasFn(MFn::kTransform)) { cameraTransform = new MFnTransform(camera.parent(i)); continue; } } // start camera description m_params.outCameras << "camera " << cameraTransform->partialPathName().asChar() << "\n"; m_params.outCameras << "{\n"; //write camera type m_params.outCameras << "\ttype "; if (camera.isOrtho()) m_params.outCameras << "ortho\n"; else m_params.outCameras << "persp\n"; // write translation data m_params.outCameras << "\ttranslation\n"; m_params.outCameras << "\t{\n"; //translateX m_params.outCameras << "\t\tx "; plug = cameraTransform->findPlug("translateX"); if (plug.isConnected() && m_params.exportCamerasAnim) { plug.connectedTo(srcplugarray,true,false,&stat); for (int i=0; i < srcplugarray.length(); i++) { if (srcplugarray[i].node().hasFn(MFn::kAnimCurve)) { if (animCurve) delete animCurve; animCurve = new MFnAnimCurve(srcplugarray[i].node()); continue; } else if (i == srcplugarray.length()-1) { std::cout << "Invalid link to translateX attribute\n"; return MS::kFailure; } } m_params.outCameras << "anim " << animCurve->name().asChar() << "\n"; } else { plug.getValue(dist); m_params.outCameras << "= " << dist << "\n"; } //translateY m_params.outCameras << "\t\ty "; plug = cameraTransform->findPlug("translateY"); if (plug.isConnected() && m_params.exportCamerasAnim) { plug.connectedTo(srcplugarray,true,false,&stat); for (int i=0; i< srcplugarray.length(); i++) { if (srcplugarray[i].node().hasFn(MFn::kAnimCurve)) { if (animCurve) delete animCurve; animCurve = new MFnAnimCurve(srcplugarray[i].node()); continue; } else if (i == srcplugarray.length()-1) { std::cout << "Invalid link to translateY attribute\n"; return MS::kFailure; } } m_params.outCameras << "anim " << animCurve->name().asChar() << "\n"; } else { plug.getValue(dist); m_params.outCameras << "= " << dist << "\n"; } //translateZ m_params.outCameras << "\t\tz "; plug = cameraTransform->findPlug("translateZ"); if (plug.isConnected() && m_params.exportCamerasAnim) { plug.connectedTo(srcplugarray,true,false,&stat); for (int i=0; i< srcplugarray.length(); i++) { if (srcplugarray[i].node().hasFn(MFn::kAnimCurve)) { if (animCurve) delete animCurve; animCurve = new MFnAnimCurve(srcplugarray[i].node()); continue; } else if (i == srcplugarray.length()-1) { std::cout << "Invalid link to translateZ attribute\n"; return MS::kFailure; } } m_params.outCameras << "anim " << animCurve->name().asChar() << "\n"; } else { plug.getValue(dist); m_params.outCameras << "= " << dist << "\n"; } m_params.outCameras << "\t}\n"; // write rotation data m_params.outCameras << "\trotation\n"; m_params.outCameras << "\t{\n"; m_params.outCameras << "\t\tx "; //rotateX plug = cameraTransform->findPlug("rotateX"); if (plug.isConnected() && m_params.exportCamerasAnim) { plug.connectedTo(srcplugarray,true,false,&stat); for (int i=0; i< srcplugarray.length(); i++) { if (srcplugarray[i].node().hasFn(MFn::kAnimCurve)) { if (animCurve) delete animCurve; animCurve = new MFnAnimCurve(srcplugarray[i].node()); continue; } else if (i == srcplugarray.length()-1) { std::cout << "Invalid link to rotateX attribute\n"; return MS::kFailure; } } m_params.outCameras << "anim " << animCurve->name().asChar() << "\n"; } else { plug.getValue(angle); m_params.outCameras << "= " << angle.asDegrees() << "\n"; } //rotateY m_params.outCameras << "\t\ty "; plug = cameraTransform->findPlug("rotateY"); if (plug.isConnected() && m_params.exportCamerasAnim) { plug.connectedTo(srcplugarray,true,false,&stat); for (int i=0; i< srcplugarray.length(); i++) { if (srcplugarray[i].node().hasFn(MFn::kAnimCurve)) { if (animCurve) delete animCurve; animCurve = new MFnAnimCurve(srcplugarray[i].node()); continue; } else if (i == srcplugarray.length()-1) { std::cout << "Invalid link to rotateY attribute\n"; return MS::kFailure; } } m_params.outCameras << "anim " << animCurve->name().asChar() << "\n"; } else { plug.getValue(angle); m_params.outCameras << "= " << angle.asDegrees() << "\n"; } //rotateZ m_params.outCameras << "\t\tz "; plug = cameraTransform->findPlug("rotateZ"); if (plug.isConnected() && m_params.exportCamerasAnim) { plug.connectedTo(srcplugarray,true,false,&stat); for (int i=0; i< srcplugarray.length(); i++) { if (srcplugarray[i].node().hasFn(MFn::kAnimCurve)) { if (animCurve) delete animCurve; animCurve = new MFnAnimCurve(srcplugarray[i].node()); continue; } else if (i == srcplugarray.length()-1) { std::cout << "Invalid link to rotateZ attribute\n"; return MS::kFailure; } } m_params.outCameras << "anim " << animCurve->name().asChar() << "\n"; } else { plug.getValue(angle); m_params.outCameras << "= " << angle.asDegrees() << "\n"; } m_params.outCameras << "\t}\n"; // end camera description m_params.outCameras << "}\n\n"; if (cameraTransform != NULL) delete cameraTransform; if (animCurve != NULL) delete animCurve; return MS::kSuccess; }