diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 64ee0bc869..236daf6443 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -210,9 +210,12 @@ public: }; glm::mat4 getGlobalTransform(const QMultiMap& _connectionParentMap, - const QHash& models, QString nodeID, bool mixamoHack) { + const QHash& models, QString nodeID, bool mixamoHack, const QString& url) { glm::mat4 globalTransform; + QVector visitedNodes; // Used to prevent following a cycle while (!nodeID.isNull()) { + visitedNodes.append(nodeID); // Append each node we visit + const FBXModel& model = models.value(nodeID); globalTransform = glm::translate(model.translation) * model.preTransform * glm::mat4_cast(model.preRotation * model.rotation * model.postRotation) * model.postTransform * globalTransform; @@ -223,6 +226,11 @@ glm::mat4 getGlobalTransform(const QMultiMap& _connectionParen QList parentIDs = _connectionParentMap.values(nodeID); nodeID = QString(); foreach (const QString& parentID, parentIDs) { + if (visitedNodes.contains(parentID)) { + qCWarning(modelformat) << "Ignoring loop detected in FBX connection map for" << url; + continue; + } + if (models.contains(parentID)) { nodeID = parentID; break; @@ -347,10 +355,18 @@ void addBlendshapes(const ExtractedBlendshape& extracted, const QList& connectionParentMap, - const QHash& models, const QString& modelID) { + const QHash& models, const QString& modelID, const QString& url) { QString topID = modelID; + QVector visitedNodes; // Used to prevent following a cycle forever { + visitedNodes.append(topID); // Append each node we visit + foreach (const QString& parentID, connectionParentMap.values(topID)) { + if (visitedNodes.contains(parentID)) { + qCWarning(modelformat) << "Ignoring loop detected in FBX connection map for" << url; + continue; + } + if (models.contains(parentID)) { topID = parentID; goto outerContinue; @@ -1307,7 +1323,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS if (!clusters.contains(clusterID)) { continue; } - QString topID = getTopModelID(_connectionParentMap, models, _connectionChildMap.value(clusterID)); + QString topID = getTopModelID(_connectionParentMap, models, _connectionChildMap.value(clusterID), url); _connectionChildMap.remove(_connectionParentMap.take(model.key()), model.key()); _connectionParentMap.insert(model.key(), topID); goto outerBreak; @@ -1329,7 +1345,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS first = id; } } - QString topID = getTopModelID(_connectionParentMap, models, first); + QString topID = getTopModelID(_connectionParentMap, models, first, url); appendModelIDs(_connectionParentMap.value(topID), _connectionChildMap, models, remainingModels, modelIDs); } @@ -1511,7 +1527,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS // accumulate local transforms QString modelID = models.contains(it.key()) ? it.key() : _connectionParentMap.value(it.key()); - glm::mat4 modelTransform = getGlobalTransform(_connectionParentMap, models, modelID, geometry.applicationName == "mixamo.com"); + glm::mat4 modelTransform = getGlobalTransform(_connectionParentMap, models, modelID, geometry.applicationName == "mixamo.com", url); // compute the mesh extents from the transformed vertices foreach (const glm::vec3& vertex, extracted.mesh.vertices) {