diff --git a/src/ExportableMesh.cpp b/src/ExportableMesh.cpp index 355e4d9..3122c28 100644 --- a/src/ExportableMesh.cpp +++ b/src/ExportableMesh.cpp @@ -13,8 +13,7 @@ #include "MeshSkeleton.h" #include "accessors.h" -ExportableMesh::ExportableMesh(ExportableScene &scene, ExportableNode &node, - const MDagPath &shapeDagPath) +ExportableMesh::ExportableMesh(ExportableScene &scene, ExportableNode &node, const MDagPath &shapeDagPath) : ExportableObject(shapeDagPath.node()) { MStatus status; @@ -38,8 +37,7 @@ ExportableMesh::ExportableMesh(ExportableScene &scene, ExportableNode &node, MeshRenderables renderables(mayaMesh->allShapes(), args); const auto &shadingMap = mainShape.indices().shadingPerInstance(); const auto &shading = shadingMap.at(renderables.instanceNumber); - const auto shaderCount = - static_cast(shading.shaderGroups.length()); + const auto shaderCount = static_cast(shading.shaderGroups.length()); /* TODO: Implement overrides auto mainDagPath = mainShape.dagPath(); @@ -68,17 +66,14 @@ ExportableMesh::ExportableMesh(ExportableScene &scene, ExportableNode &node, const auto &vertexBuffer = pair.second; const int shaderIndex = vertexSignature.shaderIndex; - auto &shaderGroup = - shaderIndex >= 0 && shaderIndex < shaderCount - ? shading.shaderGroups[shaderIndex] - : MObject::kNullObj; + auto &shaderGroup = shaderIndex >= 0 && shaderIndex < shaderCount ? shading.shaderGroups[shaderIndex] + : MObject::kNullObj; ExportableMaterial *material = nullptr; // Assign material to primitive if (args.colorizeMaterials) { - const float h = - vertexBufferIndex * 1.0f / vertexBufferCount; + const float h = vertexBufferIndex * 1.0f / vertexBufferCount; const float s = shaderCount == 0 ? 0.5f : 1; const float v = shaderIndex < 0 ? 0.5f : 1; material = resources.getDebugMaterial({h, s, v}); @@ -89,36 +84,27 @@ ExportableMesh::ExportableMesh(ExportableScene &scene, ExportableNode &node, } if (material) { - const auto primitiveName = - shapeName + "#" + std::to_string(vertexBufferIndex); + const auto primitiveName = shapeName + "#" + std::to_string(vertexBufferIndex); auto exportablePrimitive = - std::make_unique( - primitiveName, vertexBuffer, resources, material); - glMesh.primitives.push_back( - &exportablePrimitive->glPrimitive); + std::make_unique(primitiveName, vertexBuffer, resources, material); + glMesh.primitives.push_back(&exportablePrimitive->glPrimitive); m_primitives.emplace_back(std::move(exportablePrimitive)); if (args.debugTangentVectors) { - auto debugPrimitive = - std::make_unique( - primitiveName, vertexBuffer, resources, - Semantic::Kind::TANGENT, ShapeIndex::main(), - args.debugVectorLength, Color({1, 0, 0, 1})); - glMesh.primitives.push_back( - &debugPrimitive->glPrimitive); + auto debugPrimitive = std::make_unique( + primitiveName, vertexBuffer, resources, Semantic::Kind::TANGENT, ShapeIndex::main(), + args.debugVectorLength, Color({1, 0, 0, 1})); + glMesh.primitives.push_back(&debugPrimitive->glPrimitive); m_primitives.emplace_back(move(debugPrimitive)); } if (args.debugNormalVectors) { - auto debugPrimitive = - std::make_unique( - primitiveName, vertexBuffer, resources, - Semantic::Kind::NORMAL, ShapeIndex::main(), - args.debugVectorLength, Color({1, 1, 0, 1})); - glMesh.primitives.push_back( - &debugPrimitive->glPrimitive); + auto debugPrimitive = std::make_unique( + primitiveName, vertexBuffer, resources, Semantic::Kind::NORMAL, ShapeIndex::main(), + args.debugVectorLength, Color({1, 1, 0, 1})); + glMesh.primitives.push_back(&debugPrimitive->glPrimitive); m_primitives.emplace_back(move(debugPrimitive)); } } @@ -134,17 +120,13 @@ ExportableMesh::ExportableMesh(ExportableScene &scene, ExportableNode &node, MString weight = shape->weightPlug.name(); weight.split('.', weightArrays); - m_morphTargetNames->addName( - weightArrays.length() <= 1 - ? std::string("morph_") + - std::to_string(m_morphTargetNames->size()) - : std::string(weightArrays[1].asChar())); + m_morphTargetNames->addName(weightArrays.length() <= 1 + ? std::string("morph_") + std::to_string(m_morphTargetNames->size()) + : std::string(weightArrays[1].asChar())); } } if (!mayaMesh->allShapes().empty()) { - glMesh.extras.insert( - {"targetNames", - static_cast(m_morphTargetNames.get())}); + glMesh.extras.insert({"targetNames", static_cast(m_morphTargetNames.get())}); } } @@ -155,19 +137,17 @@ ExportableMesh::ExportableMesh(ExportableScene &scene, ExportableNode &node, auto &joints = skeleton.joints(); - std::map> distanceToRootMap; + // std::map> distanceToRootMap; m_inverseBindMatrices.reserve(joints.size()); // Get joints, and build inverse bind matrices. for (auto &joint : joints) { auto *jointNode = joint.node; - glSkin.joints.emplace_back( - const_cast(&jointNode->glPrimaryNode())); + glSkin.joints.emplace_back(const_cast(&jointNode->glPrimaryNode())); - auto distanceToRoot = - ExportableScene::distanceToRoot(jointNode->dagPath); - distanceToRootMap[distanceToRoot].emplace_back(jointNode); + // auto distanceToRoot = ExportableScene::distanceToRoot(jointNode->dagPath); + // distanceToRootMap[distanceToRoot].emplace_back(jointNode); double ibm[4][4]; THROW_ON_FAILURE(joint.inverseBindMatrix.get(ibm)); @@ -176,8 +156,7 @@ ExportableMesh::ExportableMesh(ExportableScene &scene, ExportableNode &node, for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { - inverseBindMatrix[i][j] = - roundToFloat(ibm[i][j], matPrecision); + inverseBindMatrix[i][j] = roundToFloat(ibm[i][j], matPrecision); } } @@ -185,8 +164,7 @@ ExportableMesh::ExportableMesh(ExportableScene &scene, ExportableNode &node, } m_inverseBindMatricesAccessor = contiguousChannelAccessor( - args.makeName(shapeName + "/skin/IBM"), - reinterpret_span(m_inverseBindMatrices), 16); + args.makeName(shapeName + "/skin/IBM"), reinterpret_span(m_inverseBindMatrices), 16); glSkin.inverseBindMatrices = m_inverseBindMatricesAccessor.get(); @@ -212,8 +190,7 @@ ExportableMesh::ExportableMesh(ExportableScene &scene, ExportableNode &node, ExportableMesh::~ExportableMesh() = default; -void ExportableMesh::getAllAccessors( - std::vector &accessors) const { +void ExportableMesh::getAllAccessors(std::vector &accessors) const { for (auto &&primitive : m_primitives) { primitive->getAllAccessors(accessors); } diff --git a/src/ExportableScene.cpp b/src/ExportableScene.cpp index ece064b..1e08661 100644 --- a/src/ExportableScene.cpp +++ b/src/ExportableScene.cpp @@ -4,8 +4,7 @@ #include "ExportableScene.h" #include "MayaException.h" -ExportableScene::ExportableScene(ExportableResources &resources) - : m_resources(resources) {} +ExportableScene::ExportableScene(ExportableResources &resources) : m_resources(resources) {} ExportableScene::~ExportableScene() = default; @@ -43,8 +42,7 @@ ExportableNode *ExportableScene::getNode(const MDagPath &dagPath) { MObject mayaNode = dagPath.node(&status); if (mayaNode.isNull() || status.error()) { - cerr << "glTF2Maya: skipping '" << fullDagPath - << "' as it is not a node" << endl; + cerr << "glTF2Maya: skipping '" << fullDagPath << "' as it is not a node" << endl; return nullptr; } @@ -57,20 +55,25 @@ ExportableNode *ExportableScene::getNode(const MDagPath &dagPath) { } ExportableNode *ExportableScene::getParent(ExportableNode *node) { - MStatus status; - - auto parentDagPath = node->dagPath; + auto dagPath = node->dagPath; ExportableNode *parentNode = nullptr; - // Find first selected ancestor node. - // That is our logical parent. + MDagPath parentDagPath; + if (findLogicalParent(dagPath, parentDagPath)) { + // Logical parent overrides Maya's parent. + // TODO: Check for cycles! + parentNode = getNode(parentDagPath); + } + + // Find first ancestor that is a Maya node. + // That will become our glTF parent. while (!parentNode) { - parentDagPath.pop(); - if (parentDagPath.length() <= 0) + dagPath.pop(); + if (dagPath.length() <= 0) break; - parentNode = getNode(parentDagPath); + parentNode = getNode(dagPath); } return parentNode; @@ -84,18 +87,56 @@ void ExportableScene::getAllAccessors(AccessorsPerDagPath &accessors) { } } -void ExportableScene::registerOrphanNode(ExportableNode *node) { - m_orphans[node->dagPath] = node; -} +void ExportableScene::registerOrphanNode(ExportableNode *node) { m_orphans[node->dagPath] = node; } + +// int ExportableScene::distanceToRoot(MDagPath dagPath) { +// int distance; +// +// // Find first ancestor node. +// // That is our logical parent. +// for (distance = 0; dagPath.length() > 0; ++distance) { +// dagPath.pop(); +// } +// +// return distance; +// } + +bool ExportableScene::findLogicalParent(const MFnDagNode &childDagNode, MDagPath &parentDagPath) { + parentDagPath = MDagPath(); + + const auto childName = childDagNode.partialPathName(); + + const auto logicalParentPlug = childDagNode.findPlug("Maya2glTF_LogicalParent"); + if (logicalParentPlug.isNull()) + return false; + + MString logicalParentName; + if (!logicalParentPlug.getValue(logicalParentName)) + return false; + + MSelectionList selection; + selection.add(logicalParentName); + if (selection.length() == 0) { + cout << prefix << "WARNING: Logical parent '" << logicalParentName.asChar() << " not found on node '" + << childName << "'" << endl; + return false; + } -int ExportableScene::distanceToRoot(MDagPath dagPath) { - int distance; + if (selection.length() > 1) { + cout << prefix << "WARNING: More than one logical parent matching '" << logicalParentName.asChar() + << " was found on node '" << childName << "'" << endl; + return false; + } - // Find first selected ancestor node. - // That is our logical parent. - for (distance = 0; dagPath.length() > 0; ++distance) { - dagPath.pop(); + MDagPath logicalParentDagPath; + if (!selection.getDagPath(0, logicalParentDagPath)) { + cout << prefix << "WARNING: Failed to get DAG path of logical parent '" << logicalParentName.asChar() + << " on node '" << childName << "'" << endl; + return false; } - return distance; + parentDagPath = logicalParentDagPath; + cout << prefix << "Found logical parent '" << logicalParentDagPath.partialPathName().asChar() << " on node '" + << childName << "'" << endl; + return true; } diff --git a/src/ExportableScene.h b/src/ExportableScene.h index 038813a..eca7809 100644 --- a/src/ExportableScene.h +++ b/src/ExportableScene.h @@ -11,8 +11,7 @@ typedef std::map> NodeTable; // sure we get a deterministic output (pointers change) typedef std::map OrphanNodes; -typedef std::map, MDagPathComparer> - AccessorsPerDagPath; +typedef std::map, MDagPathComparer> AccessorsPerDagPath; // Maps each DAG path to the corresponding node // Owns and creates each node on the fly. @@ -45,7 +44,7 @@ class ExportableScene { // Register a node without parent void registerOrphanNode(ExportableNode *node); - static int distanceToRoot(MDagPath dagPath); + // static int distanceToRoot(MDagPath dagPath); const NodeTable &table() const { return m_table; } @@ -56,6 +55,8 @@ class ExportableScene { friend class ExportableNode; + static bool findLogicalParent(const MFnDagNode &childDagNode, MDagPath &parentDagPath); + ExportableResources &m_resources; NodeTable m_table; NodeTransformCache m_initialTransformCache;