Skip to content

Commit

Permalink
NEW: Ability to set logical parents, to override Maya's hierarchy. No…
Browse files Browse the repository at this point in the history
… cycle detection yet!
  • Loading branch information
ziriax committed Aug 4, 2020
1 parent fc0ec18 commit c13125a
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 75 deletions.
77 changes: 27 additions & 50 deletions src/ExportableMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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<int>(shading.shaderGroups.length());
const auto shaderCount = static_cast<int>(shading.shaderGroups.length());

/* TODO: Implement overrides
auto mainDagPath = mainShape.dagPath();
Expand Down Expand Up @@ -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});
Expand All @@ -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<ExportablePrimitive>(
primitiveName, vertexBuffer, resources, material);
glMesh.primitives.push_back(
&exportablePrimitive->glPrimitive);
std::make_unique<ExportablePrimitive>(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<ExportablePrimitive>(
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<ExportablePrimitive>(
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<ExportablePrimitive>(
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<ExportablePrimitive>(
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));
}
}
Expand All @@ -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<GLTF::Object *>(m_morphTargetNames.get())});
glMesh.extras.insert({"targetNames", static_cast<GLTF::Object *>(m_morphTargetNames.get())});
}
}

Expand All @@ -155,19 +137,17 @@ ExportableMesh::ExportableMesh(ExportableScene &scene, ExportableNode &node,

auto &joints = skeleton.joints();

std::map<int, std::vector<ExportableNode *>> distanceToRootMap;
// std::map<int, std::vector<ExportableNode *>> 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<GLTF::Node *>(&jointNode->glPrimaryNode()));
glSkin.joints.emplace_back(const_cast<GLTF::Node *>(&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));
Expand All @@ -176,17 +156,15 @@ 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);
}
}

m_inverseBindMatrices.emplace_back(inverseBindMatrix);
}

m_inverseBindMatricesAccessor = contiguousChannelAccessor(
args.makeName(shapeName + "/skin/IBM"),
reinterpret_span<float>(m_inverseBindMatrices), 16);
args.makeName(shapeName + "/skin/IBM"), reinterpret_span<float>(m_inverseBindMatrices), 16);

glSkin.inverseBindMatrices = m_inverseBindMatricesAccessor.get();

Expand All @@ -212,8 +190,7 @@ ExportableMesh::ExportableMesh(ExportableScene &scene, ExportableNode &node,

ExportableMesh::~ExportableMesh() = default;

void ExportableMesh::getAllAccessors(
std::vector<GLTF::Accessor *> &accessors) const {
void ExportableMesh::getAllAccessors(std::vector<GLTF::Accessor *> &accessors) const {
for (auto &&primitive : m_primitives) {
primitive->getAllAccessors(accessors);
}
Expand Down
85 changes: 63 additions & 22 deletions src/ExportableScene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
Expand All @@ -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;
}
7 changes: 4 additions & 3 deletions src/ExportableScene.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ typedef std::map<std::string, std::unique_ptr<ExportableNode>> NodeTable;
// sure we get a deterministic output (pointers change)
typedef std::map<MDagPath, ExportableNode *, MDagPathComparer> OrphanNodes;

typedef std::map<MDagPath, std::vector<GLTF::Accessor *>, MDagPathComparer>
AccessorsPerDagPath;
typedef std::map<MDagPath, std::vector<GLTF::Accessor *>, MDagPathComparer> AccessorsPerDagPath;

// Maps each DAG path to the corresponding node
// Owns and creates each node on the fly.
Expand Down Expand Up @@ -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; }

Expand All @@ -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;
Expand Down

0 comments on commit c13125a

Please sign in to comment.