void MayaTransformWriter::pushTransformStack(const MFnTransform & iTrans, bool iForceStatic) { // inspect the translate addTranslate(iTrans, "translate", "translateX", "translateY", "translateZ", Alembic::AbcGeom::kTranslateHint, false, iForceStatic, false, mSample, mAnimChanList); // inspect the rotate pivot translate addTranslate(iTrans, "rotatePivotTranslate", "rotatePivotTranslateX", "rotatePivotTranslateY", "rotatePivotTranslateZ", Alembic::AbcGeom::kRotatePivotTranslationHint, false, iForceStatic, false, mSample, mAnimChanList); // inspect the rotate pivot addTranslate(iTrans, "rotatePivot", "rotatePivotX", "rotatePivotY", "rotatePivotZ", Alembic::AbcGeom::kRotatePivotPointHint, false, iForceStatic, false, mSample, mAnimChanList); // inspect rotate names MString rotateNames[3]; rotateNames[0] = "rotateX"; rotateNames[1] = "rotateY"; rotateNames[2] = "rotateZ"; unsigned int rotOrder[3]; // if this returns false then the rotation order was kInvalid or kLast MTransformationMatrix::RotationOrder eRotOrder(iTrans.rotationOrder()); if (util::getRotOrder(eRotOrder, rotOrder[0], rotOrder[1], rotOrder[2])) { addRotate(iTrans, "rotate", rotateNames, rotOrder, Alembic::AbcGeom::kRotateHint, iForceStatic, false, mSample, mAnimChanList, mRotateOpIndex); } // now look at the rotation orientation, aka rotate axis rotateNames[0] = "rotateAxisX"; rotateNames[1] = "rotateAxisY"; rotateNames[2] = "rotateAxisZ"; rotOrder[0] = 0; rotOrder[1] = 1; rotOrder[2] = 2; addRotate(iTrans, "rotateAxis", rotateNames, rotOrder, Alembic::AbcGeom::kRotateOrientationHint, iForceStatic, false, mSample, mAnimChanList, mRotateAxisOpIndex); // invert the rotate pivot if necessary addTranslate(iTrans, "rotatePivot", "rotatePivotX", "rotatePivotY", "rotatePivotZ", Alembic::AbcGeom::kRotatePivotPointHint, true, iForceStatic, false, mSample, mAnimChanList); // inspect the scale pivot translation addTranslate(iTrans, "scalePivotTranslate", "scalePivotTranslateX", "scalePivotTranslateY", "scalePivotTranslateZ", Alembic::AbcGeom::kScalePivotTranslationHint, false, iForceStatic, false, mSample, mAnimChanList); // inspect the scale pivot point addTranslate(iTrans, "scalePivot", "scalePivotX", "scalePivotY", "scalePivotZ", Alembic::AbcGeom::kScalePivotPointHint, false, iForceStatic, false, mSample, mAnimChanList); // inspect the shear addShear(iTrans, iForceStatic, mSample, mAnimChanList); // add the scale addScale(iTrans, "scale", "scaleX", "scaleY", "scaleZ", false, iForceStatic, false, mSample, mAnimChanList); // inverse the scale pivot point if necessary addTranslate(iTrans, "scalePivot", "scalePivotX", "scalePivotY", "scalePivotZ", Alembic::AbcGeom::kScalePivotPointHint, true, iForceStatic, false, mSample, mAnimChanList); // remember current rotation if (mFilterEulerRotations) { double xx(0), yy(0), zz(0); // there are 2 rotation order enum definitions: // MEulerRotation::RotationOrder = MTransformationMatrix::RotationOrder-1 if (getSampledRotation( mSample, mRotateOpIndex, xx, yy, zz )) { mPrevRotateSolution.setValue(xx, yy, zz, (MEulerRotation::RotationOrder)(eRotOrder-1)); } if (getSampledRotation( mSample, mRotateAxisOpIndex, xx, yy, zz )) { mPrevRotateAxisSolution.setValue(xx, yy, zz, MEulerRotation::kXYZ); } } }
// 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; }
void MayaTransformWriter::pushTransformStack(double iFrame, const MFnTransform & iTrans) { bool forceStatic = (iFrame == DBL_MAX); // inspect the translate addTranslate(iTrans, "translate", "translateX", "translateY", "translateZ", Alembic::AbcGeom::kTranslateHint, false, forceStatic, mSample, mAnimChanList); // inspect the rotate pivot translate addTranslate(iTrans, "rotatePivotTranslate", "rotatePivotTranslateX", "rotatePivotTranslateY", "rotatePivotTranslateZ", Alembic::AbcGeom::kRotatePivotTranslationHint, false, forceStatic, mSample, mAnimChanList); // inspect the rotate pivot addTranslate(iTrans, "rotatePivot", "rotatePivotX", "rotatePivotY", "rotatePivotZ", Alembic::AbcGeom::kRotatePivotPointHint, false, forceStatic, mSample, mAnimChanList); // inspect rotate names MString rotateNames[3]; rotateNames[0] = "rotateX"; rotateNames[1] = "rotateY"; rotateNames[2] = "rotateZ"; unsigned int rotOrder[3]; // if this returns false then the rotation order was kInvalid or kLast if (util::getRotOrder(iTrans.rotationOrder(), rotOrder[0], rotOrder[1], rotOrder[2])) { addRotate(iTrans, "rotate", rotateNames, rotOrder, Alembic::AbcGeom::kRotateHint, forceStatic, false, mSample, mAnimChanList); } // now look at the rotation orientation, aka rotate axis rotateNames[0] = "rotateAxisX"; rotateNames[1] = "rotateAxisY"; rotateNames[2] = "rotateAxisZ"; rotOrder[0] = 0; rotOrder[1] = 1; rotOrder[2] = 2; addRotate(iTrans, "rotateAxis", rotateNames, rotOrder, Alembic::AbcGeom::kRotateOrientationHint, forceStatic, false, mSample, mAnimChanList); // invert the rotate pivot if necessary addTranslate(iTrans, "rotatePivot", "rotatePivotX", "rotatePivotY", "rotatePivotZ", Alembic::AbcGeom::kRotatePivotPointHint, true, forceStatic, mSample, mAnimChanList); // inspect the scale pivot translation addTranslate(iTrans, "scalePivotTranslate", "scalePivotTranslateX", "scalePivotTranslateY", "scalePivotTranslateZ", Alembic::AbcGeom::kScalePivotTranslationHint, false, forceStatic, mSample, mAnimChanList); // inspect the scale pivot point addTranslate(iTrans, "scalePivot", "scalePivotX", "scalePivotY", "scalePivotZ", Alembic::AbcGeom::kScalePivotPointHint, false, forceStatic, mSample, mAnimChanList); // inspect the shear addShear(iTrans, forceStatic, mSample, mAnimChanList); // add the scale addScale(iTrans, "scale", "scaleX", "scaleY", "scaleZ", forceStatic, mSample, mAnimChanList); // inverse the scale pivot point if necessary addTranslate(iTrans, "scalePivot", "scalePivotX", "scalePivotY", "scalePivotZ", Alembic::AbcGeom::kScalePivotPointHint, true, forceStatic, mSample, mAnimChanList); }