Skip to content

Commit

Permalink
Merge pull request #2942 from dgovil/euler-filter-on-import
Browse files Browse the repository at this point in the history
Added applyEulerFilter to import
  • Loading branch information
seando-adsk authored Mar 30, 2023
2 parents acf4a71 + dfcce4b commit 0b7a959
Show file tree
Hide file tree
Showing 11 changed files with 212 additions and 13 deletions.
5 changes: 5 additions & 0 deletions lib/mayaUsd/commands/baseImportCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ MSyntax MayaUSDImportCommand::createSyntax()
MSyntax::kString);
syntax.makeFlagMultiUse(kImportChaserArgsFlag);

syntax.addFlag(
kApplyEulerFilterFlag,
UsdMayaJobImportArgsTokens->applyEulerFilter.GetText(),
MSyntax::kBoolean);

// These are additional flags under our control.
syntax.addFlag(kFileFlag, kFileFlagLong, MSyntax::kString);
syntax.addFlag(kParentFlag, kParentFlagLong, MSyntax::kString);
Expand Down
1 change: 1 addition & 0 deletions lib/mayaUsd/commands/baseImportCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class MAYAUSD_CORE_PUBLIC MayaUSDImportCommand : public MPxCommand
static constexpr auto kUseAsAnimationCacheFlag = "uac";
static constexpr auto kImportChaserFlag = "chr";
static constexpr auto kImportChaserArgsFlag = "cha";
static constexpr auto kApplyEulerFilterFlag = "aef";

// Short and Long forms of flags defined by this command itself:
static constexpr auto kFileFlag = "f";
Expand Down
6 changes: 6 additions & 0 deletions lib/mayaUsd/fileio/importData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ ImportData::ImportData()
, fRootPrimPath(kRootPrimPath)
, fPrimsInScopeCount(0)
, fSwitchedVariantCount(0)
, fApplyEulerFilter(false)
{
}

Expand All @@ -39,6 +40,7 @@ ImportData::ImportData(const std::string& f)
, fFilename(f)
, fPrimsInScopeCount(0)
, fSwitchedVariantCount(0)
, fApplyEulerFilter(false)
{
}

Expand Down Expand Up @@ -88,6 +90,10 @@ void ImportData::setRootPrimPath(const std::string& primPath) { fRootPrimPath =

bool ImportData::hasPopulationMask() const { return !fPopMask.IsEmpty(); }

void ImportData::setApplyEulerFilter(bool value) { fApplyEulerFilter = value; }

bool ImportData::applyEulerFilter() const { return fApplyEulerFilter; }

const UsdStagePopulationMask& ImportData::stagePopulationMask() const { return fPopMask; }

void ImportData::setStagePopulationMask(const UsdStagePopulationMask& mask) { fPopMask = mask; }
Expand Down
11 changes: 9 additions & 2 deletions lib/mayaUsd/fileio/importData.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ class MAYAUSD_CORE_PUBLIC ImportData
//! \return True if the USD population mask is not empty.
bool hasPopulationMask() const;

//! Apply euler filter to imported rotation animCurves
void setApplyEulerFilter(bool value);

//! \return True if the imported rotation curves should be euler filtered
bool applyEulerFilter() const;

//! \return The USD population mask of the stage to use for import.
const UsdStagePopulationMask& stagePopulationMask() const;

Expand Down Expand Up @@ -134,8 +140,9 @@ class MAYAUSD_CORE_PUBLIC ImportData
std::string fRootPrimPath;
std::string fFilename;

int fPrimsInScopeCount;
int fSwitchedVariantCount;
int fPrimsInScopeCount;
int fSwitchedVariantCount;
bool fApplyEulerFilter;
};

} // namespace MAYAUSD_NS_DEF
6 changes: 5 additions & 1 deletion lib/mayaUsd/fileio/jobs/jobArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,7 @@ UsdMayaJobImportArgs::UsdMayaJobImportArgs(
, useAsAnimationCache(extractBoolean(userArgs, UsdMayaJobImportArgsTokens->useAsAnimationCache))
, importWithProxyShapes(importWithProxyShapes)
, preserveTimeline(extractBoolean(userArgs, UsdMayaJobImportArgsTokens->preserveTimeline))
, applyEulerFilter(extractBoolean(userArgs, UsdMayaJobImportArgsTokens->applyEulerFilter))
, pullImportStage(extractUsdStageRefPtr(userArgs, UsdMayaJobImportArgsTokens->pullImportStage))
, timeInterval(timeInterval)
, chaserNames(extractVector<std::string>(userArgs, UsdMayaJobImportArgsTokens->chaser))
Expand Down Expand Up @@ -1169,6 +1170,7 @@ const VtDictionary& UsdMayaJobImportArgs::GetDefaultDictionary()
d[UsdMayaJobImportArgsTokens->preserveTimeline] = false;
d[UsdMayaJobExportArgsTokens->chaser] = std::vector<VtValue>();
d[UsdMayaJobExportArgsTokens->chaserArgs] = std::vector<VtValue>();
d[UsdMayaJobImportArgsTokens->applyEulerFilter] = false;

// plugInfo.json site defaults.
// The defaults dict should be correctly-typed, so enable
Expand Down Expand Up @@ -1247,6 +1249,7 @@ const VtDictionary& UsdMayaJobImportArgs::GetGuideDictionary()
d[UsdMayaJobImportArgsTokens->preserveTimeline] = _boolean;
d[UsdMayaJobExportArgsTokens->chaser] = _stringVector;
d[UsdMayaJobExportArgsTokens->chaserArgs] = _stringTripletVector;
d[UsdMayaJobImportArgsTokens->applyEulerFilter] = _boolean;
});

return d;
Expand Down Expand Up @@ -1334,7 +1337,8 @@ std::ostream& operator<<(std::ostream& out, const UsdMayaJobImportArgs& importAr
<< "timeInterval: " << importArgs.timeInterval << std::endl
<< "useAsAnimationCache: " << TfStringify(importArgs.useAsAnimationCache) << std::endl
<< "preserveTimeline: " << TfStringify(importArgs.preserveTimeline) << std::endl
<< "importWithProxyShapes: " << TfStringify(importArgs.importWithProxyShapes) << std::endl;
<< "importWithProxyShapes: " << TfStringify(importArgs.importWithProxyShapes) << std::endl
<< "applyEulerFilter: " << importArgs.applyEulerFilter << std::endl;

out << "jobContextNames (" << importArgs.jobContextNames.size() << ")" << std::endl;
for (const std::string& jobContextName : importArgs.jobContextNames) {
Expand Down
4 changes: 3 additions & 1 deletion lib/mayaUsd/fileio/jobs/jobArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ TF_DECLARE_PUBLIC_TOKENS(
(Import) \
((Unloaded, "")) \
(chaser) \
(chaserArgs)
(chaserArgs) \
(applyEulerFilter)
// clang-format on

TF_DECLARE_PUBLIC_TOKENS(
Expand Down Expand Up @@ -338,6 +339,7 @@ struct UsdMayaJobImportArgs
const bool useAsAnimationCache;
const bool importWithProxyShapes;
const bool preserveTimeline;
const bool applyEulerFilter;
const UsdStageRefPtr pullImportStage;
/// The interval over which to import animated data.
/// An empty interval (<tt>GfInterval::IsEmpty()</tt>) means that no
Expand Down
30 changes: 27 additions & 3 deletions lib/mayaUsd/fileio/translators/translatorSkel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <maya/MDGModifier.h>
#include <maya/MDagModifier.h>
#include <maya/MDoubleArray.h>
#include <maya/MEulerRotation.h>
#include <maya/MFnAnimCurve.h>
#include <maya/MFnComponentListData.h>
#include <maya/MFnDependencyNode.h>
Expand Down Expand Up @@ -214,7 +215,8 @@ bool _SetTransformAnim(
MFnDependencyNode& transformNode,
const std::vector<GfMatrix4d>& xforms,
MTimeArray& times,
const UsdMayaPrimReaderContext* context)
const UsdMayaPrimReaderContext* context,
bool applyEulerFilter)
{
if (xforms.size() != times.length()) {
TF_WARN("xforms size [%zu] != times size [%du].", xforms.size(), times.length());
Expand Down Expand Up @@ -249,6 +251,22 @@ bool _SetTransformAnim(
}
}

if (applyEulerFilter) {
MPlug rotOrder = transformNode.findPlug("rotateOrder");
MEulerRotation::RotationOrder order
= static_cast<MEulerRotation::RotationOrder>(rotOrder.asInt());

MEulerRotation last(rotates[0][0], rotates[1][0], rotates[2][0], order);
for (unsigned int i = 1; i < rotates[0].length(); ++i) {
MEulerRotation current(rotates[0][i], rotates[1][i], rotates[2][i], order);
current.setToClosestSolution(last);
rotates[0][i] = current[0];
rotates[1][i] = current[1];
rotates[2][i] = current[2];
last = current;
}
}

for (int c = 0; c < 3; ++c) {
if (!_SetAnimPlugData(
transformNode, _MayaTokens->translates[c], translates[c], times, context)
Expand Down Expand Up @@ -502,7 +520,12 @@ bool _CopyAnimFromSkel(
MFnDependencyNode skelXformDep(jointContainer, &status);
CHECK_MSTATUS_AND_RETURN(status, false);

if (!_SetTransformAnim(skelXformDep, skelLocalXforms, mayaTimes, context)) {
if (!_SetTransformAnim(
skelXformDep,
skelLocalXforms,
mayaTimes,
context,
args.GetJobArguments().applyEulerFilter)) {
return false;
}
}
Expand Down Expand Up @@ -540,7 +563,8 @@ bool _CopyAnimFromSkel(
xforms[i] = samples[i][jointIdx];
}

if (!_SetTransformAnim(jointDep, xforms, mayaTimes, context))
if (!_SetTransformAnim(
jointDep, xforms, mayaTimes, context, args.GetJobArguments().applyEulerFilter))
return false;
}
return true;
Expand Down
46 changes: 40 additions & 6 deletions lib/mayaUsd/fileio/translators/translatorXformable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@
#include <maya/MFnAnimCurve.h>
#include <maya/MFnDependencyNode.h>
#include <maya/MFnTransform.h>
#include <maya/MGlobal.h>
#include <maya/MMatrix.h>
#include <maya/MObjectArray.h>
#include <maya/MPlug.h>
#include <maya/MStatus.h>
#include <maya/MString.h>
Expand Down Expand Up @@ -120,7 +122,7 @@ _getXformOpAsVec3d(const UsdGeomXformOp& xformOp, GfVec3d& value, const UsdTimeC
}

// Sets the animation curve (a knot per frame) for a given plug/attribute
static void _setAnimPlugData(
static MObject _setAnimPlugData(
MPlug plg,
std::vector<double>& value,
MTimeArray& timeArray,
Expand All @@ -144,6 +146,8 @@ static void _setAnimPlugData(
TF_RUNTIME_ERROR(
"Failed to create animation object for attribute: %s", mayaPlgName.asChar());
}

return animObj;
}

// Returns true if the array is not constant
Expand Down Expand Up @@ -172,31 +176,57 @@ static void _setMayaAttribute(
const MString& x,
const MString& y,
const MString& z,
const UsdMayaPrimReaderContext* context)
const UsdMayaPrimReaderContext* context,
bool applyEulerFilter = false)
{

// if have multiple values, and applyEulerFilter, filter the values
//
if (applyEulerFilter && opName == "rotate") {
if (xVal.size() == static_cast<size_t>(timeArray.length()) && xVal.size() == yVal.size()
&& xVal.size() == zVal.size()) {
MPlug rotOrder = depFn.findPlug("rotateOrder");
MEulerRotation::RotationOrder order
= static_cast<MEulerRotation::RotationOrder>(rotOrder.asInt());

MEulerRotation last(xVal[0], yVal[0], zVal[0], order);
for (size_t i = 1; i < xVal.size(); ++i) {
MEulerRotation current(xVal[i], yVal[i], zVal[i], order);
current.setToClosestSolution(last);
xVal[i] = current[0];
yVal[i] = current[1];
zVal[i] = current[2];
last = current;
}
}
}

MPlug plg;
if (x != "" && !xVal.empty()) {
plg = depFn.findPlug(opName + x);
if (!plg.isNull()) {
plg.setDouble(xVal[0]);
if (xVal.size() > 1 && _isArrayVarying(xVal))
if (xVal.size() > 1 && (applyEulerFilter || _isArrayVarying(xVal))) {
_setAnimPlugData(plg, xVal, timeArray, context);
}
}
}
if (y != "" && !yVal.empty()) {
plg = depFn.findPlug(opName + y);
if (!plg.isNull()) {
plg.setDouble(yVal[0]);
if (yVal.size() > 1 && _isArrayVarying(yVal))
if (yVal.size() > 1 && (applyEulerFilter || _isArrayVarying(yVal))) {
_setAnimPlugData(plg, yVal, timeArray, context);
}
}
}
if (z != "" && !zVal.empty()) {
plg = depFn.findPlug(opName + z);
if (!plg.isNull()) {
plg.setDouble(zVal[0]);
if (zVal.size() > 1 && _isArrayVarying(zVal))
if (zVal.size() > 1 && (applyEulerFilter || _isArrayVarying(zVal))) {
_setAnimPlugData(plg, zVal, timeArray, context);
}
}
}
}
Expand All @@ -218,6 +248,9 @@ static bool _pushUSDXformOpToMayaXform(
std::vector<double> zValue;
GfVec3d value;
std::vector<double> timeSamples;

bool applyEulerFilter = args.GetJobArguments().applyEulerFilter;

if (!args.GetTimeInterval().IsEmpty()) {
xformop.GetTimeSamplesInInterval(args.GetTimeInterval(), &timeSamples);
}
Expand Down Expand Up @@ -352,7 +385,8 @@ static bool _pushUSDXformOpToMayaXform(
"X",
"Y",
"Z",
context);
context,
applyEulerFilter && opName == UsdMayaXformStackTokens->rotate);
}
return true;
}
Expand Down
2 changes: 2 additions & 0 deletions plugin/adsk/plugin/importTranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ MStatus UsdMayaImportTranslator::reader(
timeInterval.SetMax(theOption[1].asDouble());
} else if (argName == "primPath") {
importData.setRootPrimPath(theOption[1].asChar());
} else if (argName == "applyEulerFilter") {
importData.setApplyEulerFilter(theOption[1].asInt() != 0);
} else {
userArgs[argName] = UsdMayaUtil::ParseArgumentValue(
argName, theOption[1].asChar(), UsdMayaJobImportArgs::GetGuideDictionary());
Expand Down
1 change: 1 addition & 0 deletions test/lib/usd/translators/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ set(TEST_SCRIPT_FILES
testUsdImportSkeleton.py
testUsdImportXforms.py
testUsdImportXformAnim.py
testUsdImportEulerFilter.py
testUsdMayaAdaptor.py
testUsdMayaAdaptorGeom.py
testUsdMayaAdaptorMetadata.py
Expand Down
Loading

0 comments on commit 0b7a959

Please sign in to comment.