diff --git a/src/animalrigger.cpp b/src/animalrigger.cpp index 90ada6ac..91c2071b 100644 --- a/src/animalrigger.cpp +++ b/src/animalrigger.cpp @@ -5,8 +5,9 @@ #include "animalrigger.h" AnimalRigger::AnimalRigger(const std::vector &verticesPositions, - const std::set &inputTriangles) : - Rigger(verticesPositions, inputTriangles) + const std::set &inputTriangles, + const std::vector, std::pair>> &triangleLinks) : + Rigger(verticesPositions, inputTriangles, triangleLinks) { } diff --git a/src/animalrigger.h b/src/animalrigger.h index 0ebf8e7a..d57d70ff 100644 --- a/src/animalrigger.h +++ b/src/animalrigger.h @@ -11,7 +11,8 @@ class AnimalRigger: public Rigger Q_OBJECT public: AnimalRigger(const std::vector &verticesPositions, - const std::set &inputTriangles); + const std::set &inputTriangles, + const std::vector, std::pair>> &triangleLinks); protected: bool validate() override; bool isCutOffSplitter(BoneMark boneMark) override; diff --git a/src/meshsplitter.cpp b/src/meshsplitter.cpp index 0d9f43e2..796b8255 100644 --- a/src/meshsplitter.cpp +++ b/src/meshsplitter.cpp @@ -4,6 +4,7 @@ #include "meshsplitter.h" bool MeshSplitter::split(const std::set &input, + const std::vector, std::pair>> &triangleLinks, std::set &splitter, std::set &firstGroup, std::set &secondGroup, @@ -21,6 +22,22 @@ bool MeshSplitter::split(const std::set &input, } } + std::map, MeshSplitterTriangle> edgeToLinkedTriangleMap; + for (const auto &it: triangleLinks) { + auto firstEdge = std::make_pair((int)it.first.first, (int)it.first.second); + auto secondEdge = std::make_pair((int)it.second.first, (int)it.second.second); + auto findFirstTriangle = edgeToTriangleMap.find(firstEdge); + auto findSecondTriangle = edgeToTriangleMap.find(secondEdge); + if (findFirstTriangle == edgeToTriangleMap.end()) + continue; + if (findSecondTriangle == edgeToTriangleMap.end()) + continue; + edgeToLinkedTriangleMap[firstEdge] = findSecondTriangle->second; + edgeToLinkedTriangleMap[std::make_pair(firstEdge.second, firstEdge.first)] = findSecondTriangle->second; + edgeToLinkedTriangleMap[secondEdge] = findFirstTriangle->second; + edgeToLinkedTriangleMap[std::make_pair(secondEdge.second, secondEdge.first)] = findFirstTriangle->second; + } + // Expand the splitter if needed if (expandSplitter) { std::vector expandedTriangles; @@ -29,12 +46,10 @@ bool MeshSplitter::split(const std::set &input, int next = (i + 1) % 3; auto oppositeEdge = std::make_pair(triangle.indices[next], triangle.indices[i]); auto oppositeTriangle = edgeToTriangleMap.find(oppositeEdge); - if (oppositeTriangle == edgeToTriangleMap.end()) { - qDebug() << "Find opposite edge failed:" << oppositeEdge.first << oppositeEdge.second; - continue; - } - if (splitter.find(oppositeTriangle->second) == splitter.end()) { - expandedTriangles.push_back(oppositeTriangle->second); + if (oppositeTriangle != edgeToTriangleMap.end()) { + if (splitter.find(oppositeTriangle->second) == splitter.end()) { + expandedTriangles.push_back(oppositeTriangle->second); + } } } } @@ -61,7 +76,7 @@ bool MeshSplitter::split(const std::set &input, auto oppositeTriangle = edgeToTriangleMap.find(oppositeEdge); if (oppositeTriangle == edgeToTriangleMap.end()) { qDebug() << "Find opposite edge failed:" << oppositeEdge.first << oppositeEdge.second; - return false; + continue; } if (splitter.find(oppositeTriangle->second) == splitter.end()) { foundStartTriangle = true; @@ -92,12 +107,16 @@ bool MeshSplitter::split(const std::set &input, int next = (i + 1) % 3; auto oppositeEdge = std::make_pair(triangle.indices[next], triangle.indices[i]); auto oppositeTriangle = edgeToTriangleMap.find(oppositeEdge); - if (oppositeTriangle == edgeToTriangleMap.end()) { - qDebug() << "Find opposite edge failed:" << oppositeEdge.first << oppositeEdge.second; - return false; + if (oppositeTriangle != edgeToTriangleMap.end()) { + if (processedTriangles.find(oppositeTriangle->second) == processedTriangles.end()) { + waitQueue.push(oppositeTriangle->second); + } } - if (processedTriangles.find(oppositeTriangle->second) == processedTriangles.end()) { - waitQueue.push(oppositeTriangle->second); + auto linkedTriangle = edgeToLinkedTriangleMap.find(oppositeEdge); + if (linkedTriangle != edgeToLinkedTriangleMap.end()) { + if (processedTriangles.find(linkedTriangle->second) == processedTriangles.end()) { + waitQueue.push(linkedTriangle->second); + } } } } diff --git a/src/meshsplitter.h b/src/meshsplitter.h index 10e42d60..1369c32d 100644 --- a/src/meshsplitter.h +++ b/src/meshsplitter.h @@ -1,6 +1,7 @@ #ifndef DUST3D_MESH_SPLITTER_H #define DUST3D_MESH_SPLITTER_H #include +#include class MeshSplitterTriangle { @@ -17,7 +18,8 @@ public: class MeshSplitter { public: - static bool split(const std::set &input, + static bool split(const std::set &input, + const std::vector, std::pair>> &triangleLinks, std::set &splitter, std::set &firstGroup, std::set &secondGroup, diff --git a/src/outcome.h b/src/outcome.h index 909f78e9..81d15c8b 100644 --- a/src/outcome.h +++ b/src/outcome.h @@ -124,6 +124,18 @@ public: m_hasPartUvRects = true; } + const std::vector, std::pair>> *triangleLinks() const + { + if (!m_hasTriangleLinks) + return nullptr; + return &m_triangleLinks; + } + void setTriangleLinks(const std::vector, std::pair>> &triangleLinks) + { + m_triangleLinks = triangleLinks; + m_hasTriangleLinks = true; + } + private: bool m_hasTriangleSourceNodes = false; std::vector> m_triangleSourceNodes; @@ -139,6 +151,9 @@ private: bool m_hasPartUvRects = false; std::map> m_partUvRects; + + bool m_hasTriangleLinks = false; + std::vector, std::pair>> m_triangleLinks; }; #endif diff --git a/src/riggenerator.cpp b/src/riggenerator.cpp index 7aff17bb..8fa43a14 100644 --- a/src/riggenerator.cpp +++ b/src/riggenerator.cpp @@ -6,6 +6,7 @@ #include "riggenerator.h" #include "riggerconstruct.h" #include "boundingboxmesh.h" +#include "triangleislandslink.h" RigGenerator::RigGenerator(RigType rigType, const Outcome &outcome) : m_rigType(rigType), @@ -141,7 +142,11 @@ void RigGenerator::generate() combinedMarkedNodesList.push_back(newNodes); } - m_autoRigger = newRigger(m_rigType, inputVerticesPositions, inputTriangles); + std::vector, std::pair>> triangleLinks; + triangleIslandsLink(*m_outcome, triangleLinks); + m_outcome->setTriangleLinks(triangleLinks); + + m_autoRigger = newRigger(m_rigType, inputVerticesPositions, inputTriangles, triangleLinks); if (nullptr == m_autoRigger) { qDebug() << "Unsupported rig type:" << RigTypeToString(m_rigType); } else { diff --git a/src/rigger.cpp b/src/rigger.cpp index bf8f3f5a..4967bb70 100644 --- a/src/rigger.cpp +++ b/src/rigger.cpp @@ -10,9 +10,11 @@ QString Rigger::rootBoneName = "Body"; //QString Rigger::firstSpineBoneName = "Spine1"; Rigger::Rigger(const std::vector &verticesPositions, - const std::set &inputTriangles) : + const std::set &inputTriangles, + const std::vector, std::pair>> &triangleLinks) : m_verticesPositions(verticesPositions), m_inputTriangles(inputTriangles), + m_triangleLinks(triangleLinks), m_extraMessagedAdded(false) { } @@ -83,7 +85,7 @@ bool Rigger::addMarkGroup(BoneMark boneMark, SkeletonSide boneSide, QVector3D bo mark.markTriangles = markTriangles; if (isCutOffSplitter(mark.boneMark)) { - if (!mark.split(m_verticesPositions, m_inputTriangles, m_maxCutOffSplitterExpandRound)) { + if (!mark.split(m_verticesPositions, m_inputTriangles, m_triangleLinks, m_maxCutOffSplitterExpandRound)) { m_cutoffErrorItems.push_back(SkeletonSideToDispName(mark.boneSide) + " " + BoneMarkToDispName(mark.boneMark)); return false; } diff --git a/src/rigger.h b/src/rigger.h index a75d09ef..6ba5525b 100644 --- a/src/rigger.h +++ b/src/rigger.h @@ -27,13 +27,14 @@ public: { return m_isFirstBiggerThenSecond ? m_secondGroup : m_firstGroup; } - bool split(const std::vector &verticesPositions, const std::set &input, int expandRound=0) + bool split(const std::vector &verticesPositions, const std::set &input, + const std::vector, std::pair>> &triangleLinks, int expandRound=0) { int totalRound = 1 + expandRound; for (int round = 0; round < totalRound; ++round) { m_firstGroup.clear(); m_secondGroup.clear(); - bool splitResult = MeshSplitter::split(input, markTriangles, m_firstGroup, m_secondGroup, round > 0); + bool splitResult = MeshSplitter::split(input, triangleLinks, markTriangles, m_firstGroup, m_secondGroup, round > 0); if (splitResult) { sortByDistanceFromOrigin(verticesPositions); return true; @@ -125,7 +126,8 @@ class Rigger : public QObject Q_OBJECT public: Rigger(const std::vector &verticesPositions, - const std::set &inputTriangles); + const std::set &inputTriangles, + const std::vector, std::pair>> &triangleLinks); bool addMarkGroup(BoneMark boneMark, SkeletonSide boneSide, QVector3D bonePosition, float nodeRadius, const std::set &markTriangles); const std::vector> &messages(); const std::vector &resultBones(); @@ -155,6 +157,7 @@ protected: std::vector> m_messages; std::vector m_verticesPositions; std::set m_inputTriangles; + std::vector, std::pair>> m_triangleLinks; std::vector m_marks; std::map, std::vector> m_marksMap; std::vector m_resultBones; diff --git a/src/riggerconstruct.cpp b/src/riggerconstruct.cpp index 147628e8..48271e8c 100644 --- a/src/riggerconstruct.cpp +++ b/src/riggerconstruct.cpp @@ -2,9 +2,10 @@ #include "animalrigger.h" Rigger *newRigger(RigType rigType, const std::vector &verticesPositions, - const std::set &inputTriangles) + const std::set &inputTriangles, + const std::vector, std::pair>> &triangleLinks) { if (rigType == RigType::Animal) - return new AnimalRigger(verticesPositions, inputTriangles); + return new AnimalRigger(verticesPositions, inputTriangles, triangleLinks); return nullptr; -} \ No newline at end of file +} diff --git a/src/riggerconstruct.h b/src/riggerconstruct.h index 39f53a2c..27f1413b 100644 --- a/src/riggerconstruct.h +++ b/src/riggerconstruct.h @@ -5,6 +5,7 @@ #include "poser.h" Rigger *newRigger(RigType rigType, const std::vector &verticesPositions, - const std::set &inputTriangles); + const std::set &inputTriangles, + const std::vector, std::pair>> &triangleLinks); #endif diff --git a/src/triangleislandslink.cpp b/src/triangleislandslink.cpp index 6ce74e08..781988b2 100644 --- a/src/triangleislandslink.cpp +++ b/src/triangleislandslink.cpp @@ -140,31 +140,30 @@ static bool fetchCgalMeshCenter(CgalMesh *cgalMesh, QVector3D ¢er) return true; } -static size_t findNearestTriangle(const Outcome &outcome, +static std::pair findNearestTriangleEdge(const Outcome &outcome, const std::vector &group, const QVector3D &point) { float minLength2 = std::numeric_limits::max(); - size_t choosenIndex = 0; + std::pair choosenEdge = std::make_pair(0, 0); for (const auto &triangleIndex: group) { - QVector3D sumOfPositions; const auto &indices = outcome.triangles[triangleIndex]; - for (const auto &it: indices) { - sumOfPositions += outcome.vertices[it]; - } - QVector3D triangleCenter = sumOfPositions / indices.size(); - float length2 = (point - triangleCenter).lengthSquared(); - if (length2 < minLength2) { - minLength2 = length2; - choosenIndex = triangleIndex; + for (size_t i = 0; i < indices.size(); ++i) { + size_t j = (i + 1) % indices.size(); + QVector3D edgeMiddle = (outcome.vertices[indices[i]] + outcome.vertices[indices[j]]) / 2; + float length2 = (point - edgeMiddle).lengthSquared(); + if (length2 < minLength2) { + minLength2 = length2; + choosenEdge = std::make_pair(indices[i], indices[j]); + } } } - return choosenIndex; + return choosenEdge; } static bool mergeIntersectedConvexMeshesAndLinkTriangles(const Outcome &outcome, std::map>> &convexMeshes, - std::vector> &links) + std::vector, std::pair>> &links) { if (convexMeshes.size() <= 1) return false; @@ -181,8 +180,8 @@ static bool mergeIntersectedConvexMeshesAndLinkTriangles(const Outcome &outcome, QString secondGroupName = it.first; std::vector firstGroupTriangleIndices = head.second.second; std::vector secondGroupTriangleIndices = it.second.second; - size_t firstGroupChoosenIndex = findNearestTriangle(outcome, firstGroupTriangleIndices, center); - size_t secondGroupChoosenIndex = findNearestTriangle(outcome, secondGroupTriangleIndices, center); + std::pair firstGroupChoosenIndex = findNearestTriangleEdge(outcome, firstGroupTriangleIndices, center); + std::pair secondGroupChoosenIndex = findNearestTriangleEdge(outcome, secondGroupTriangleIndices, center); links.push_back(std::make_pair(firstGroupChoosenIndex, secondGroupChoosenIndex)); std::vector triangleIndices(firstGroupTriangleIndices); triangleIndices.insert(triangleIndices.end(), secondGroupTriangleIndices.begin(), secondGroupTriangleIndices.end()); @@ -201,7 +200,7 @@ static bool mergeIntersectedConvexMeshesAndLinkTriangles(const Outcome &outcome, } void triangleIslandsLink(const Outcome &outcome, - std::vector> &links) + std::vector, std::pair>> &links) { std::vector group; std::vector> islands; diff --git a/src/triangleislandslink.h b/src/triangleislandslink.h index 80ad2054..5d4e9789 100644 --- a/src/triangleislandslink.h +++ b/src/triangleislandslink.h @@ -4,6 +4,6 @@ #include "outcome.h" void triangleIslandsLink(const Outcome &outcome, - std::vector> &links); + std::vector, std::pair>> &links); #endif