diff --git a/src/Arguments.cpp b/src/Arguments.cpp index a30509a..fab1769 100644 --- a/src/Arguments.cpp +++ b/src/Arguments.cpp @@ -90,6 +90,8 @@ const auto constantRotationThreshold = "crt"; const auto constantScalingThreshold = "cst"; const auto constantWeightsThreshold = "cwt"; +const auto keepObjectNamespace = "kon"; + } // namespace flag inline const char *getArgTypeName(const MSyntax::MArgType argType) { @@ -182,7 +184,7 @@ SyntaxFactory::SyntaxFactory() { registerFlag(ss, flag::forceRootNode, "forceRootNode", kNoArg); registerFlag(ss, flag::forceAnimationChannels, "forceAnimationChannels", kNoArg); registerFlag(ss, flag::forceAnimationSampling, "forceAnimationSampling", kNoArg); - + registerFlag(ss, flag::hashBufferURIs, "hashBufferUri", kNoArg); registerFlag(ss, flag::niceBufferURIs, "niceBufferNames", kNoArg); @@ -197,6 +199,8 @@ SyntaxFactory::SyntaxFactory() { registerFlag(ss, flag::constantScalingThreshold, "constantScalingThreshold", kDouble); registerFlag(ss, flag::constantWeightsThreshold, "constantWeightsThreshold", kDouble); + registerFlag(ss, flag::keepObjectNamespace, "keepMayaNamespaces", kNoArg); + m_usage = ss.str(); } @@ -212,13 +216,11 @@ MSyntax SyntaxFactory::createSyntax() { return s; } -void SyntaxFactory::registerFlag(std::stringstream &ss, const char *shortName, const char *longName, - const MArgType argType1) { +void SyntaxFactory::registerFlag(std::stringstream &ss, const char *shortName, const char *longName, const MArgType argType1) { registerFlag(ss, shortName, longName, false, argType1); } -void SyntaxFactory::registerFlag(std::stringstream &ss, const char *shortName, const char *longName, - const bool isMultiUse, const MArgType argType1) { +void SyntaxFactory::registerFlag(std::stringstream &ss, const char *shortName, const char *longName, const bool isMultiUse, const MArgType argType1) { // short-name should be unique assert(m_argNames.find(shortName) == m_argNames.end()); @@ -297,8 +299,7 @@ class ArgChecker { int flagUsageCount(const char *shortName) const { return adb.numberOfFlagUses(shortName); } - template - void required(const char *shortName, T &value, const int flagIndex = 0, const int componentIndex = 0) const { + template void required(const char *shortName, T &value, const int flagIndex = 0, const int componentIndex = 0) const { MStatus status; if (!isFlagSet(shortName)) @@ -310,16 +311,13 @@ class ArgChecker { } else { MArgList args; status = adb.getFlagArgumentList(shortName, flagIndex, args); - throwOnArgument(status, shortName, - formatted("Failed to get required multi-flag #%d argument", flagIndex).c_str()); + throwOnArgument(status, shortName, formatted("Failed to get required multi-flag #%d argument", flagIndex).c_str()); status = args.get(componentIndex, value); - throwOnArgument(status, shortName, - formatted("Failed to get required multi-flag #%d argument value", flagIndex).c_str()); + throwOnArgument(status, shortName, formatted("Failed to get required multi-flag #%d argument value", flagIndex).c_str()); } } - template - bool optional(const char *shortName, T &value, const int flagIndex = 0, const int componentIndex = 0) const { + template bool optional(const char *shortName, T &value, const int flagIndex = 0, const int componentIndex = 0) const { if (!adb.isFlagSet(shortName)) return false; @@ -331,11 +329,9 @@ class ArgChecker { } else { MArgList args; status = adb.getFlagArgumentList(shortName, flagIndex, args); - throwOnArgument(status, shortName, - formatted("Failed to get optional multi-flag #%d argument", flagIndex).c_str()); + throwOnArgument(status, shortName, formatted("Failed to get optional multi-flag #%d argument", flagIndex).c_str()); status = args.get(componentIndex, value); - throwOnArgument(status, shortName, - formatted("Failed to get optional multi-flag #%d argument value", flagIndex).c_str()); + throwOnArgument(status, shortName, formatted("Failed to get optional multi-flag #%d argument value", flagIndex).c_str()); } return true; @@ -357,8 +353,7 @@ class ArgChecker { return true; } - std::unique_ptr getOutputStream(const char *arg, const char *outputName, - const fs::path &outputFolder, + std::unique_ptr getOutputStream(const char *arg, const char *outputName, const fs::path &outputFolder, std::ofstream &fileOutputStream) const { std::ostream *out = nullptr; @@ -401,10 +396,8 @@ class ArgChecker { const auto longArgName = SyntaxFactory::get().longArgName(shortArgName); const auto statusStr = status.errorString().asChar(); const auto usageStr = SyntaxFactory::get().usage(); - throw MayaException( - status, message ? formatted("-%s (-%s): %s\nUsage:\n%s", shortArgName, longArgName, statusStr, usageStr) - : formatted("-%s (-%s): %s %s\nUsage:\n%s", shortArgName, longArgName, message, - statusStr, usageStr)); + throw MayaException(status, message ? formatted("-%s (-%s): %s\nUsage:\n%s", shortArgName, longArgName, statusStr, usageStr) + : formatted("-%s (-%s): %s %s\nUsage:\n%s", shortArgName, longArgName, message, statusStr, usageStr)); } } @@ -412,8 +405,7 @@ class ArgChecker { const auto longArgName = SyntaxFactory::get().longArgName(shortArgName); const auto usageStr = SyntaxFactory::get().usage(); - throw MayaException(MStatus::kInvalidParameter, - formatted("%s -%s (%s)\nUsage:\n%s", message, shortArgName, longArgName, usageStr)); + throw MayaException(MStatus::kInvalidParameter, formatted("%s -%s (%s)\nUsage:\n%s", message, shortArgName, longArgName, usageStr)); } private: @@ -479,6 +471,7 @@ Arguments::Arguments(const MArgList &args, const MSyntax &syntax) { force32bitIndices = adb.isFlagSet(flag::force32bitIndices); disableNameAssignment = adb.isFlagSet(flag::disableNameAssignment); + keepObjectNamespace = adb.isFlagSet(flag::keepObjectNamespace); skipSkinClusters = adb.isFlagSet(flag::skipSkinClusters); skipBlendShapes = adb.isFlagSet(flag::skipBlendShapes); redrawViewport = adb.isFlagSet(flag::redrawViewport); @@ -573,8 +566,7 @@ Arguments::Arguments(const MArgList &args, const MSyntax &syntax) { // Print the animation clips for (const auto &clip : animationClips) { cout << prefix << "Exporting clip " << clip.name << ", start:" << clip.startTime << ", end: " << clip.endTime - << ", duration:" << clip.duration() << ", frames: " << clip.frameCount() - << ", rate: " << clip.framesPerSecond << "fps" << endl; + << ", duration:" << clip.duration() << ", frames: " << clip.frameCount() << ", rate: " << clip.framesPerSecond << "fps" << endl; } // Get extra cameras to export @@ -607,8 +599,7 @@ Arguments::Arguments(const MArgList &args, const MSyntax &syntax) { unsigned shapeCount; status = dagPath.numberOfShapesDirectlyBelow(shapeCount); if (!status) { - cerr << prefix << "Skipping " << dagPath.partialPathName() << ", it has no shapes attached to it" - << endl; + cerr << prefix << "Skipping " << dagPath.partialPathName() << ", it has no shapes attached to it" << endl; continue; } @@ -629,8 +620,7 @@ Arguments::Arguments(const MArgList &args, const MSyntax &syntax) { } if (!foundCameraShape) { - cerr << prefix << "Skipping " << dagPath.partialPathName() << ", it has no cameras attached to it" - << endl; + cerr << prefix << "Skipping " << dagPath.partialPathName() << ", it has no cameras attached to it" << endl; continue; } } @@ -670,8 +660,43 @@ Arguments::~Arguments() { } } -void Arguments::select(Selection &shapeSelection, Selection &cameraSelection, const MDagPath &dagPath, - const bool includeDescendants, const bool includeInvisibleNodes) { +std::string Arguments::assignName(GLTF::Object &glObj, const MDagPath &dagPath, const MString &suffix) const { + MStatus status; + auto obj = dagPath.node(&status); + THROW_ON_FAILURE(status) + + const MFnDependencyNode node(obj, &status); + THROW_ON_FAILURE(status) + + return assignName(glObj, node, suffix); +} + +std::string Arguments::assignName(GLTF::Object &glObj, const MFnDependencyNode &node, const MString &suffix) const { + MStatus status; + + auto name = node.name(&status); + THROW_ON_FAILURE(status) + + if (!keepObjectNamespace) { + const auto ns = node.parentNamespace(&status); + if (status && ns.length() > 0) { + name.substitute(ns + ":", ""); + } + } + + name += suffix; + + std::string result(name.asChar()); + + if (!disableNameAssignment) { + glObj.name = result; + } + + return result; +} + +void Arguments::select(Selection &shapeSelection, Selection &cameraSelection, const MDagPath &dagPath, const bool includeDescendants, + const bool includeInvisibleNodes) { MStatus status; std::string debugName{dagPath.partialPathName().asChar()}; diff --git a/src/Arguments.h b/src/Arguments.h index 9676d5f..7eeb629 100644 --- a/src/Arguments.h +++ b/src/Arguments.h @@ -27,8 +27,7 @@ class SyntaxFactory : MSyntax { std::map m_argNames; std::string m_usage; - void registerFlag(std::stringstream &ss, const char *shortName, const char *longName, bool isMultiUse, - MArgType argType1 = kNoArg); + void registerFlag(std::stringstream &ss, const char *shortName, const char *longName, bool isMultiUse, MArgType argType1 = kNoArg); void registerFlag(std::stringstream &ss, const char *shortName, const char *longName, MArgType argType1 = kNoArg); }; @@ -48,9 +47,7 @@ struct AnimClipArg { }; struct MDagPathComparer { - bool operator()(const MDagPath &a, const MDagPath &b) const { - return strcmp(a.fullPathName().asChar(), b.fullPathName().asChar()) < 0; - } + bool operator()(const MDagPath &a, const MDagPath &b) const { return strcmp(a.fullPathName().asChar(), b.fullPathName().asChar()) < 0; } }; typedef std::set Selection; @@ -141,6 +138,9 @@ class Arguments { /** By default the Maya node names are assigned to the GLTF node names */ bool disableNameAssignment = false; + /** By default we remove the Maya object namespace from GLTF node names */ + bool keepObjectNamespace = false; + /** Generate debug tangent vector lines? */ bool debugTangentVectors = false; @@ -251,11 +251,8 @@ class Arguments { /** Copyright text of the exported file */ MString copyright; - void assignName(GLTF::Object &glObj, const std::string &name) const { - if (!disableNameAssignment) { - glObj.name = name; - } - } + std::string assignName(GLTF::Object &glObj, const MDagPath &dagPath, const MString &suffix) const; + std::string assignName(GLTF::Object &glObj, const MFnDependencyNode &node, const MString &suffix) const; std::string makeName(const std::string &name) const { return disableNameAssignment ? "" : name; } @@ -265,8 +262,8 @@ class Arguments { private: DISALLOW_COPY_MOVE_ASSIGN(Arguments); - static void select(Selection &shapeSelection, Selection &cameraSelection, const MDagPath &dagPath, - bool includeDescendants, bool visibleNodesOnly); + static void select(Selection &shapeSelection, Selection &cameraSelection, const MDagPath &dagPath, bool includeDescendants, + bool visibleNodesOnly); std::ofstream m_mayaOutputFileStream; std::ofstream m_gltfOutputFileStream; diff --git a/src/ExportableCamera.cpp b/src/ExportableCamera.cpp index c17d585..27decdd 100644 --- a/src/ExportableCamera.cpp +++ b/src/ExportableCamera.cpp @@ -95,8 +95,7 @@ ExportableCamera::ExportableCamera(ExportableScene &scene, ExportableNode &node, glCamera = move(perspectiveCamera); } - const std::string cameraName{shapeDagPath.partialPathName(&status).asChar()}; - args.assignName(*glCamera, cameraName); + args.assignName(*glCamera, shapeDagPath, ""); glCamera->znear = float(camera.nearClippingPlane(&status)) * args.globalScaleFactor; THROW_ON_FAILURE(status); diff --git a/src/ExportableMaterial.cpp b/src/ExportableMaterial.cpp index b568b44..28a4204 100644 --- a/src/ExportableMaterial.cpp +++ b/src/ExportableMaterial.cpp @@ -111,7 +111,7 @@ void ExportableMaterialPBR::convert(ExportableResources &resources, const MObjec THROW_ON_FAILURE(status); auto &args = resources.arguments(); - args.assignName(m_glMaterial, shader.name().asChar()); + args.assignName(m_glMaterial, shader, ""); m_glMetallicRoughness.roughnessFactor = 1; m_glMetallicRoughness.metallicFactor = 0; @@ -165,7 +165,7 @@ void ExportableMaterialPBR::loadPBR(ExportableResources &resources, const MFnDep THROW_ON_FAILURE(status); auto &args = resources.arguments(); - args.assignName(m_glMaterial, shaderNode.name().asChar()); + args.assignName(m_glMaterial, shaderNode, ""); // Base color. For some reason Maya splits this attribute into separate RGB // and A attributes @@ -365,7 +365,7 @@ void ExportableMaterialPBR::loadAiStandard( THROW_ON_FAILURE(status); auto &args = resources.arguments(); - args.assignName(m_glMaterial, shaderNode.name().asChar()); + args.assignName(m_glMaterial, shaderNode, ""); float opacityFactor = 1.f; diff --git a/src/ExportableMesh.cpp b/src/ExportableMesh.cpp index 3122c28..5469744 100644 --- a/src/ExportableMesh.cpp +++ b/src/ExportableMesh.cpp @@ -17,8 +17,6 @@ ExportableMesh::ExportableMesh(ExportableScene &scene, ExportableNode &node, con : ExportableObject(shapeDagPath.node()) { MStatus status; - const std::string shapeName{shapeDagPath.partialPathName(&status).asChar()}; - auto &resources = scene.resources(); auto &args = resources.arguments(); @@ -29,7 +27,7 @@ ExportableMesh::ExportableMesh(ExportableScene &scene, ExportableNode &node, con } if (!mayaMesh->isEmpty()) { - args.assignName(glMesh, shapeName); + auto shapeName = args.assignName(glMesh, shapeDagPath, ""); auto &mainShape = mayaMesh->shape(); @@ -133,7 +131,7 @@ ExportableMesh::ExportableMesh(ExportableScene &scene, ExportableNode &node, con // Generate skin auto &skeleton = mainShape.skeleton(); if (!skeleton.isEmpty()) { - args.assignName(glSkin, shapeName); + args.assignName(glSkin, shapeDagPath, ""); auto &joints = skeleton.joints(); diff --git a/src/ExportableNode.cpp b/src/ExportableNode.cpp index d79fce9..6e14ed3 100644 --- a/src/ExportableNode.cpp +++ b/src/ExportableNode.cpp @@ -24,10 +24,10 @@ void ExportableNode::load(ExportableScene &scene, NodeTransformCache &transformC // Remember scale factor scaleFactor = args.getBakeScaleFactor(); - // Get name - const auto name = dagPath.partialPathName(&status); - THROW_ON_FAILURE(status); - + // // Get name + // const auto name = dagPath.partialPathName(&status); + // THROW_ON_FAILURE(status); + // // Get parent parentNode = scene.getParent(this); @@ -77,17 +77,17 @@ void ExportableNode::load(ExportableScene &scene, NodeTransformCache &transformC switch (transformKind) { case TransformKind::ComplexJoint: - args.assignName(sNode, (name + ":SSC").asChar()); - args.assignName(pNode, name.asChar()); + args.assignName(sNode, dagPath, ":SSC"); + args.assignName(pNode, dagPath, ""); sNode.children.emplace_back(&pNode); break; case TransformKind::ComplexTransform: - args.assignName(pNode, (name + ":PIV").asChar()); - args.assignName(sNode, name.asChar()); + args.assignName(pNode, dagPath, ":PIV"); + args.assignName(sNode, dagPath, ""); sNode.children.emplace_back(&pNode); break; default:; - args.assignName(pNode, name.asChar()); + args.assignName(pNode, dagPath, ""); break; } @@ -110,7 +110,7 @@ void ExportableNode::load(ExportableScene &scene, NodeTransformCache &transformC if (initialTransformState.maxNonOrthogonality > MAX_NON_ORTHOGONALITY) { // TODO: Use SVG to decompose the 3x3 matrix into a product of rotation // and scale matrices. - cerr << prefix << "WARNING: node '" << name + cerr << prefix << "WARNING: node '" << name() << "' has initial transforms that are not representable by glTF! " "Skewing is not supported, use 3 nodes to simulate this. " "Deviation = "