Skip to content

Commit

Permalink
Merge pull request #1931 from AnimalLogic/csyshing/only-bake-xform-at…
Browse files Browse the repository at this point in the history
…-top-level

Fixed worldspace export flag behaviour to only bake xform at the top level prim
  • Loading branch information
Krystian Ligenza authored Jan 12, 2022
2 parents cff3b65 + 498e146 commit 44df6f6
Show file tree
Hide file tree
Showing 6 changed files with 325 additions and 39 deletions.
147 changes: 119 additions & 28 deletions plugin/al/lib/AL_USDMaya/AL/usdmaya/fileio/Export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,49 @@ struct Export::Impl
}
}

void addSelection(MDagPath parentDagPath, const std::string& path)
{
const std::string parent(parentDagPath.fullPathName().asChar());
m_selectionMap[parent].emplace(path);
// Add all of the parent paths
m_parentsMap.emplace(parent);
while (parentDagPath.pop() == MStatus::kSuccess && parentDagPath.isValid()) {
std::string pathStr(parentDagPath.fullPathName().asChar());
if (m_parentsMap.find(pathStr) != m_parentsMap.end()) {
// Parent path has been added
return;
}
m_parentsMap.emplace(pathStr);
}
}

bool isPathExcluded(MDagPath dagPath) const
{
// Excluded path is:
// 1) path itself is not selected; AND
// 2) none of any ascendants or descendants are selected

const std::string pathStr(dagPath.fullPathName().asChar());
if (dagPath.pop() != MStatus::kSuccess || !dagPath.isValid()) {
// Path is likely the root level node
return false;
}
// Check if the target path itself is selected or not
auto it = m_selectionMap.find(dagPath.fullPathName().asChar());
if (it != m_selectionMap.cend()) {
// Found parent path in cache map, either target path or any of its siblings
// is selected
if (it->second.find(pathStr) == it->second.cend()) {
// One of the target path's sibling is selected, do further checking
// to see if any of the children is select or not.
// If not found, this target path should be excluded.
return m_parentsMap.find(pathStr) == m_parentsMap.cend();
}
// Reaching here means the target path itself is selected
}
return false;
}

private:
#if AL_UTILS_ENABLE_SIMD
std::map<i128, MObject, AL::maya::utils::guid_compare> m_nodeMap;
Expand All @@ -290,8 +333,10 @@ struct Export::Impl
std::map<AL::maya::utils::guid, MObject, AL::maya::utils::guid_compare> m_nodeMap;
std::map<AL::maya::utils::guid, SdfPath, AL::maya::utils::guid_compare> m_instanceMap;
#endif
UsdStageRefPtr m_stage;
UsdPrim m_instancesPrim;
std::unordered_map<std::string, std::unordered_set<std::string>> m_selectionMap;
std::unordered_set<std::string> m_parentsMap;
UsdStageRefPtr m_stage;
UsdPrim m_instancesPrim;
};

static MObject g_transform_rotateAttr = MObject::kNullObj;
Expand Down Expand Up @@ -509,11 +554,11 @@ void Export::exportIkChain(MDagPath effectorPath, const SdfPath& usdPath)
}

//----------------------------------------------------------------------------------------------------------------------
void Export::copyTransformParams(UsdPrim prim, MFnTransform& fnTransform)
void Export::copyTransformParams(UsdPrim prim, MFnTransform& fnTransform, bool exportInWorldSpace)
{

translators::TransformTranslator::copyAttributes(
fnTransform.object(), prim, m_params, fnTransform.dagPath());
fnTransform.object(), prim, m_params, fnTransform.dagPath(), exportInWorldSpace);
if (m_params.m_dynamicAttributes) {
translators::DgNodeTranslator::copyDynamicAttributes(
fnTransform.object(), prim, m_params.m_animTranslator);
Expand Down Expand Up @@ -564,7 +609,8 @@ void Export::addReferences(
MFnTransform& fnTransform,
SdfPath& usdPath,
const SdfPath& instancePath,
ReferenceType refType)
ReferenceType refType,
bool exportInWorldSpace)
{
UsdStageRefPtr stage = m_impl->stage();
if (refType == kShapeReference) {
Expand All @@ -583,7 +629,7 @@ void Export::addReferences(
} break;

case kShapeReference: {
copyTransformParams(usdPrim, fnTransform);
copyTransformParams(usdPrim, fnTransform, exportInWorldSpace);
} break;

default: break;
Expand All @@ -604,7 +650,8 @@ void Export::exportShapesCommonProc(
MDagPath shapePath,
MFnTransform& fnTransform,
SdfPath& usdPath,
const ReferenceType refType)
const ReferenceType refType,
bool exportInWorldSpace)
{
UsdPrim transformPrim;

Expand Down Expand Up @@ -663,7 +710,7 @@ void Export::exportShapesCommonProc(
}

if (m_params.m_mergeTransforms && copyTransform) {
copyTransformParams(transformPrim, fnTransform);
copyTransformParams(transformPrim, fnTransform, exportInWorldSpace);
}
}

Expand All @@ -687,13 +734,14 @@ void Export::exportSceneHierarchy(MDagPath rootPath, SdfPath& defaultPrim)
MItDag it(MItDag::kDepthFirst);
it.reset(rootPath, MItDag::kDepthFirst, MFn::kTransform);

std::function<void(MDagPath, MFnTransform&, SdfPath&, ReferenceType)> exportShapeProc
std::function<void(MDagPath, MFnTransform&, SdfPath&, ReferenceType, bool)> exportShapeProc
= [this](
MDagPath shapePath,
MFnTransform& fnTransform,
SdfPath& usdPath,
ReferenceType refType) {
this->exportShapesCommonProc(shapePath, fnTransform, usdPath, refType);
ReferenceType refType,
bool inWorldSpace) {
this->exportShapesCommonProc(shapePath, fnTransform, usdPath, refType, inWorldSpace);
};

std::function<bool(MDagPath, MFnTransform&, SdfPath&, bool)> exportTransformFunc
Expand All @@ -717,13 +765,13 @@ void Export::exportSceneHierarchy(MDagPath rootPath, SdfPath& defaultPrim)
if (translatorPtr) {
UsdPrim transformPrim
= translatorPtr->exportObject(m_impl->stage(), transformPath, path, m_params);
this->copyTransformParams(transformPrim, fnTransform);
this->copyTransformParams(transformPrim, fnTransform, inWorldSpace);
exportKids = translatorPtr->exportDescendants();
} else {

UsdGeomXform xform = UsdGeomXform::Define(m_impl->stage(), path);
UsdPrim transformPrim = xform.GetPrim();
this->copyTransformParams(transformPrim, fnTransform);
this->copyTransformParams(transformPrim, fnTransform, inWorldSpace);
}
return exportKids;
};
Expand All @@ -734,7 +782,8 @@ void Export::exportSceneHierarchy(MDagPath rootPath, SdfPath& defaultPrim)
MDagPath shapePath,
MFnTransform& fnTransform,
SdfPath& usdPath,
ReferenceType refType) {
ReferenceType refType,
bool inWorldSpace) {
this->exportShapesOnlyUVProc(shapePath, fnTransform, usdPath);
};
exportTransformFunc = [this](
Expand All @@ -751,17 +800,36 @@ void Export::exportSceneHierarchy(MDagPath rootPath, SdfPath& defaultPrim)
}

MFnTransform fnTransform;
bool exportInWorldSpace = m_params.m_exportInWorldSpace;
// loop through transforms only
while (!it.isDone()) {
// assign transform function set
MDagPath transformPath;
it.getPath(transformPath);

// Check if any sibling is selected, exclude this node if not selected
if (m_impl->isPathExcluded(transformPath)) {
it.prune();
it.next();
continue;
}

if (exportInWorldSpace && !(transformPath == rootPath)) {
exportInWorldSpace = false;
}

fnTransform.setObject(transformPath);

// Make sure we haven't seen this transform before.
bool transformHasBeenExported = m_impl->contains(fnTransform);
if (transformHasBeenExported) {
// "rootPath" is the user selected node but if it has been exported,
// that means user selected a sub node under another selected node.
if (transformPath == rootPath) {
it.prune();
it.next();
continue;
}
// We have an instanced shape!
std::cout << "encountered transform instance " << fnTransform.fullPathName().asChar()
<< std::endl;
Expand Down Expand Up @@ -794,9 +862,9 @@ void Export::exportSceneHierarchy(MDagPath rootPath, SdfPath& defaultPrim)
uint32_t numShapes;
transformPath.numberOfShapesDirectlyBelow(numShapes);

if (!m_params.m_mergeTransforms && !m_params.m_exportInWorldSpace) {
bool exportKids = exportTransformFunc(
transformPath, fnTransform, usdPath, m_params.m_exportInWorldSpace);
if (!m_params.m_mergeTransforms && !exportInWorldSpace) {
bool exportKids
= exportTransformFunc(transformPath, fnTransform, usdPath, exportInWorldSpace);
UsdPrim prim = m_impl->stage()->GetPrimAtPath(usdPath);
prim.SetMetadata<TfToken>(
AL::usdmaya::Metadata::mergedTransform, AL::usdmaya::Metadata::unmerged);
Expand Down Expand Up @@ -832,25 +900,38 @@ void Export::exportSceneHierarchy(MDagPath rootPath, SdfPath& defaultPrim)
refType = m_params.m_mergeTransforms ? kShapeReference
: kTransformReference;
}
exportShapeProc(shapePath, fnTransform, shapeUsdPath, refType);
exportShapeProc(
shapePath, fnTransform, shapeUsdPath, refType, exportInWorldSpace);
} else {
refType
= m_params.m_mergeTransforms ? kShapeReference : kTransformReference;
}

if (refType == kShapeReference) {
SdfPath instancePath = m_impl->getMasterPath(shapeDag);
addReferences(shapePath, fnTransform, shapeUsdPath, instancePath, refType);
addReferences(
shapePath,
fnTransform,
shapeUsdPath,
instancePath,
refType,
exportInWorldSpace);
} else if (refType == kTransformReference) {
SdfPath instancePath
= m_impl->getMasterPath(MFnDagNode(shapeDag.parent(0)));
addReferences(shapePath, fnTransform, usdPath, instancePath, refType);
addReferences(
shapePath,
fnTransform,
usdPath,
instancePath,
refType,
exportInWorldSpace);
}
}
} else {
if (m_params.m_mergeTransforms) {
if (!exportTransformFunc(
transformPath, fnTransform, usdPath, m_params.m_exportInWorldSpace)) {
transformPath, fnTransform, usdPath, exportInWorldSpace)) {
it.prune();
}
}
Expand Down Expand Up @@ -884,26 +965,36 @@ void Export::doExport()
m_impl->createInstancesPrim();
}

MObjectArray objects;
const MSelectionList& sl = m_params.m_nodes;
SdfPath defaultPrim;

// Use std::map to keep the same order regardless of the selection order from Maya
// This makes sure we process the objects from top to bottom
std::map<std::string, MDagPath> selectedPaths;
for (uint32_t i = 0, n = sl.length(); i < n; ++i) {
MDagPath path;
if (sl.getDagPath(i, path)) {
std::string pathStr;
if (path.node().hasFn(MFn::kTransform)) {
exportSceneHierarchy(path, defaultPrim);
pathStr = path.fullPathName().asChar();
} else if (path.node().hasFn(MFn::kShape)) {
path.pop();
exportSceneHierarchy(path, defaultPrim);
pathStr = path.fullPathName().asChar();
} else {
continue;
}
selectedPaths.emplace(pathStr, path);
// Store direct parent path
if (path.pop() == MStatus::kSuccess && path.isValid()) {
m_impl->addSelection(path, pathStr);
}
} else {
MObject obj;
sl.getDependNode(i, obj);
objects.append(obj);
}
}

for (const auto& pathPair : selectedPaths) {
exportSceneHierarchy(pathPair.second, defaultPrim);
}

if (m_params.m_animTranslator) {
m_params.m_animTranslator->exportAnimation(m_params);
m_impl->setAnimationFrame(m_params.m_minFrame, m_params.m_maxFrame);
Expand Down
8 changes: 5 additions & 3 deletions plugin/al/lib/AL_USDMaya/AL/usdmaya/fileio/Export.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,22 +70,24 @@ class Export
MDagPath shapePath,
MFnTransform& fnTransform,
SdfPath& usdPath,
ReferenceType refType);
ReferenceType refType,
bool exportInWorldSpace);
void exportShapesOnlyUVProc(MDagPath shapePath, MFnTransform& fnTransform, SdfPath& usdPath);
UsdPrim exportMeshUV(MDagPath path, const SdfPath& usdPath);
UsdPrim exportAssembly(MDagPath path, const SdfPath& usdPath);
UsdPrim exportPluginLocatorNode(MDagPath path, const SdfPath& usdPath);
UsdPrim exportPluginShape(MDagPath path, const SdfPath& usdPath);
void exportIkChain(MDagPath effectorPath, const SdfPath& usdPath);
void exportGeometryConstraint(MDagPath effectorPath, const SdfPath& usdPath);
void copyTransformParams(UsdPrim prim, MFnTransform& fnTransform);
void copyTransformParams(UsdPrim prim, MFnTransform& fnTransform, bool exportInWorldSpace);
SdfPath determineUsdPath(MDagPath path, const SdfPath& usdPath, ReferenceType refType);
void addReferences(
MDagPath shapePath,
MFnTransform& fnTransform,
SdfPath& usdPath,
const SdfPath& instancePath,
ReferenceType refType);
ReferenceType refType,
bool exportInWorldSpace);
inline bool isPrimDefined(SdfPath& usdPath);
struct Impl;
void doExport();
Expand Down
5 changes: 2 additions & 3 deletions plugin/al/lib/AL_USDMaya/AL/usdmaya/fileio/ExportParams.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,8 @@ struct ExporterParams
bool m_animation = false; ///< if true, animation will be exported.
bool m_useTimelineRange = false; ///< if true, then the export uses Maya's timeline range.
bool m_filterSample = false; ///< if true, duplicate sample of attribute will be filtered out
bool m_exportInWorldSpace
= false; ///< if true, transform hierarchies will be flattened to a single WS transform PRIM
///< (and no parents will be written out)
bool m_exportInWorldSpace = false; ///< if true, transform will be baked at the root prim,
///< children under the root will be untouched.
AnimationTranslator* m_animTranslator
= 0; ///< the animation translator to help exporting the animation data
bool m_extensiveAnimationCheck
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,8 @@ MStatus TransformTranslator::copyAttributes(
const MObject& from,
UsdPrim& to,
const ExporterParams& params,
const MDagPath& path)
const MDagPath& path,
bool exportInWorldSpace)
{
UsdGeomXform xformSchema(to);
GfVec3f scale;
Expand Down Expand Up @@ -698,7 +699,7 @@ MStatus TransformTranslator::copyAttributes(
transformAnimated = animTranslator->isAnimatedTransform(from);
}

if (!params.m_exportInWorldSpace) {
if (!exportInWorldSpace) {
getBool(from, m_inheritsTransform, inheritsTransform);
getBool(from, m_visible, visible);
getVec3(from, m_scale, (float*)&scale);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,15 @@ class TransformTranslator : public DagNodeTranslator
/// \param to the USD prim to copy the attributes to
/// \param params the exporter params to determine what should be exported
/// \param path the dag path
/// \param exportInWorldSpace parameter to determine if world space xform should be exported
/// \return MS::kSuccess if ok
AL_USDMAYA_PUBLIC
static MStatus copyAttributes(
const MObject& from,
UsdPrim& to,
const ExporterParams& params,
const MDagPath& path);
const MDagPath& path,
bool exportInWorldSpace);

/// \brief copy the attribute value from the plug specified, at the given time, and store the
/// data on the usdAttr. \param attr the attribute to be copied \param usdAttr the attribute
Expand Down
Loading

0 comments on commit 44df6f6

Please sign in to comment.