Support rigging for uncombined mesh.

master
Jeremy Hu 2019-10-03 08:21:38 +09:30
parent 00c05e8cb0
commit 74f5a081e3
12 changed files with 92 additions and 43 deletions

View File

@ -5,8 +5,9 @@
#include "animalrigger.h" #include "animalrigger.h"
AnimalRigger::AnimalRigger(const std::vector<QVector3D> &verticesPositions, AnimalRigger::AnimalRigger(const std::vector<QVector3D> &verticesPositions,
const std::set<MeshSplitterTriangle> &inputTriangles) : const std::set<MeshSplitterTriangle> &inputTriangles,
Rigger(verticesPositions, inputTriangles) const std::vector<std::pair<std::pair<size_t, size_t>, std::pair<size_t, size_t>>> &triangleLinks) :
Rigger(verticesPositions, inputTriangles, triangleLinks)
{ {
} }

View File

@ -11,7 +11,8 @@ class AnimalRigger: public Rigger
Q_OBJECT Q_OBJECT
public: public:
AnimalRigger(const std::vector<QVector3D> &verticesPositions, AnimalRigger(const std::vector<QVector3D> &verticesPositions,
const std::set<MeshSplitterTriangle> &inputTriangles); const std::set<MeshSplitterTriangle> &inputTriangles,
const std::vector<std::pair<std::pair<size_t, size_t>, std::pair<size_t, size_t>>> &triangleLinks);
protected: protected:
bool validate() override; bool validate() override;
bool isCutOffSplitter(BoneMark boneMark) override; bool isCutOffSplitter(BoneMark boneMark) override;

View File

@ -4,6 +4,7 @@
#include "meshsplitter.h" #include "meshsplitter.h"
bool MeshSplitter::split(const std::set<MeshSplitterTriangle> &input, bool MeshSplitter::split(const std::set<MeshSplitterTriangle> &input,
const std::vector<std::pair<std::pair<size_t, size_t>, std::pair<size_t, size_t>>> &triangleLinks,
std::set<MeshSplitterTriangle> &splitter, std::set<MeshSplitterTriangle> &splitter,
std::set<MeshSplitterTriangle> &firstGroup, std::set<MeshSplitterTriangle> &firstGroup,
std::set<MeshSplitterTriangle> &secondGroup, std::set<MeshSplitterTriangle> &secondGroup,
@ -21,6 +22,22 @@ bool MeshSplitter::split(const std::set<MeshSplitterTriangle> &input,
} }
} }
std::map<std::pair<int, int>, 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 // Expand the splitter if needed
if (expandSplitter) { if (expandSplitter) {
std::vector<MeshSplitterTriangle> expandedTriangles; std::vector<MeshSplitterTriangle> expandedTriangles;
@ -29,12 +46,10 @@ bool MeshSplitter::split(const std::set<MeshSplitterTriangle> &input,
int next = (i + 1) % 3; int next = (i + 1) % 3;
auto oppositeEdge = std::make_pair(triangle.indices[next], triangle.indices[i]); auto oppositeEdge = std::make_pair(triangle.indices[next], triangle.indices[i]);
auto oppositeTriangle = edgeToTriangleMap.find(oppositeEdge); auto oppositeTriangle = edgeToTriangleMap.find(oppositeEdge);
if (oppositeTriangle == edgeToTriangleMap.end()) { if (oppositeTriangle != edgeToTriangleMap.end()) {
qDebug() << "Find opposite edge failed:" << oppositeEdge.first << oppositeEdge.second; if (splitter.find(oppositeTriangle->second) == splitter.end()) {
continue; expandedTriangles.push_back(oppositeTriangle->second);
} }
if (splitter.find(oppositeTriangle->second) == splitter.end()) {
expandedTriangles.push_back(oppositeTriangle->second);
} }
} }
} }
@ -61,7 +76,7 @@ bool MeshSplitter::split(const std::set<MeshSplitterTriangle> &input,
auto oppositeTriangle = edgeToTriangleMap.find(oppositeEdge); auto oppositeTriangle = edgeToTriangleMap.find(oppositeEdge);
if (oppositeTriangle == edgeToTriangleMap.end()) { if (oppositeTriangle == edgeToTriangleMap.end()) {
qDebug() << "Find opposite edge failed:" << oppositeEdge.first << oppositeEdge.second; qDebug() << "Find opposite edge failed:" << oppositeEdge.first << oppositeEdge.second;
return false; continue;
} }
if (splitter.find(oppositeTriangle->second) == splitter.end()) { if (splitter.find(oppositeTriangle->second) == splitter.end()) {
foundStartTriangle = true; foundStartTriangle = true;
@ -92,12 +107,16 @@ bool MeshSplitter::split(const std::set<MeshSplitterTriangle> &input,
int next = (i + 1) % 3; int next = (i + 1) % 3;
auto oppositeEdge = std::make_pair(triangle.indices[next], triangle.indices[i]); auto oppositeEdge = std::make_pair(triangle.indices[next], triangle.indices[i]);
auto oppositeTriangle = edgeToTriangleMap.find(oppositeEdge); auto oppositeTriangle = edgeToTriangleMap.find(oppositeEdge);
if (oppositeTriangle == edgeToTriangleMap.end()) { if (oppositeTriangle != edgeToTriangleMap.end()) {
qDebug() << "Find opposite edge failed:" << oppositeEdge.first << oppositeEdge.second; if (processedTriangles.find(oppositeTriangle->second) == processedTriangles.end()) {
return false; waitQueue.push(oppositeTriangle->second);
}
} }
if (processedTriangles.find(oppositeTriangle->second) == processedTriangles.end()) { auto linkedTriangle = edgeToLinkedTriangleMap.find(oppositeEdge);
waitQueue.push(oppositeTriangle->second); if (linkedTriangle != edgeToLinkedTriangleMap.end()) {
if (processedTriangles.find(linkedTriangle->second) == processedTriangles.end()) {
waitQueue.push(linkedTriangle->second);
}
} }
} }
} }

View File

@ -1,6 +1,7 @@
#ifndef DUST3D_MESH_SPLITTER_H #ifndef DUST3D_MESH_SPLITTER_H
#define DUST3D_MESH_SPLITTER_H #define DUST3D_MESH_SPLITTER_H
#include <set> #include <set>
#include <vector>
class MeshSplitterTriangle class MeshSplitterTriangle
{ {
@ -17,7 +18,8 @@ public:
class MeshSplitter class MeshSplitter
{ {
public: public:
static bool split(const std::set<MeshSplitterTriangle> &input, static bool split(const std::set<MeshSplitterTriangle> &input,
const std::vector<std::pair<std::pair<size_t, size_t>, std::pair<size_t, size_t>>> &triangleLinks,
std::set<MeshSplitterTriangle> &splitter, std::set<MeshSplitterTriangle> &splitter,
std::set<MeshSplitterTriangle> &firstGroup, std::set<MeshSplitterTriangle> &firstGroup,
std::set<MeshSplitterTriangle> &secondGroup, std::set<MeshSplitterTriangle> &secondGroup,

View File

@ -124,6 +124,18 @@ public:
m_hasPartUvRects = true; m_hasPartUvRects = true;
} }
const std::vector<std::pair<std::pair<size_t, size_t>, std::pair<size_t, size_t>>> *triangleLinks() const
{
if (!m_hasTriangleLinks)
return nullptr;
return &m_triangleLinks;
}
void setTriangleLinks(const std::vector<std::pair<std::pair<size_t, size_t>, std::pair<size_t, size_t>>> &triangleLinks)
{
m_triangleLinks = triangleLinks;
m_hasTriangleLinks = true;
}
private: private:
bool m_hasTriangleSourceNodes = false; bool m_hasTriangleSourceNodes = false;
std::vector<std::pair<QUuid, QUuid>> m_triangleSourceNodes; std::vector<std::pair<QUuid, QUuid>> m_triangleSourceNodes;
@ -139,6 +151,9 @@ private:
bool m_hasPartUvRects = false; bool m_hasPartUvRects = false;
std::map<QUuid, std::vector<QRectF>> m_partUvRects; std::map<QUuid, std::vector<QRectF>> m_partUvRects;
bool m_hasTriangleLinks = false;
std::vector<std::pair<std::pair<size_t, size_t>, std::pair<size_t, size_t>>> m_triangleLinks;
}; };
#endif #endif

View File

@ -6,6 +6,7 @@
#include "riggenerator.h" #include "riggenerator.h"
#include "riggerconstruct.h" #include "riggerconstruct.h"
#include "boundingboxmesh.h" #include "boundingboxmesh.h"
#include "triangleislandslink.h"
RigGenerator::RigGenerator(RigType rigType, const Outcome &outcome) : RigGenerator::RigGenerator(RigType rigType, const Outcome &outcome) :
m_rigType(rigType), m_rigType(rigType),
@ -141,7 +142,11 @@ void RigGenerator::generate()
combinedMarkedNodesList.push_back(newNodes); combinedMarkedNodesList.push_back(newNodes);
} }
m_autoRigger = newRigger(m_rigType, inputVerticesPositions, inputTriangles); std::vector<std::pair<std::pair<size_t, size_t>, std::pair<size_t, size_t>>> triangleLinks;
triangleIslandsLink(*m_outcome, triangleLinks);
m_outcome->setTriangleLinks(triangleLinks);
m_autoRigger = newRigger(m_rigType, inputVerticesPositions, inputTriangles, triangleLinks);
if (nullptr == m_autoRigger) { if (nullptr == m_autoRigger) {
qDebug() << "Unsupported rig type:" << RigTypeToString(m_rigType); qDebug() << "Unsupported rig type:" << RigTypeToString(m_rigType);
} else { } else {

View File

@ -10,9 +10,11 @@ QString Rigger::rootBoneName = "Body";
//QString Rigger::firstSpineBoneName = "Spine1"; //QString Rigger::firstSpineBoneName = "Spine1";
Rigger::Rigger(const std::vector<QVector3D> &verticesPositions, Rigger::Rigger(const std::vector<QVector3D> &verticesPositions,
const std::set<MeshSplitterTriangle> &inputTriangles) : const std::set<MeshSplitterTriangle> &inputTriangles,
const std::vector<std::pair<std::pair<size_t, size_t>, std::pair<size_t, size_t>>> &triangleLinks) :
m_verticesPositions(verticesPositions), m_verticesPositions(verticesPositions),
m_inputTriangles(inputTriangles), m_inputTriangles(inputTriangles),
m_triangleLinks(triangleLinks),
m_extraMessagedAdded(false) m_extraMessagedAdded(false)
{ {
} }
@ -83,7 +85,7 @@ bool Rigger::addMarkGroup(BoneMark boneMark, SkeletonSide boneSide, QVector3D bo
mark.markTriangles = markTriangles; mark.markTriangles = markTriangles;
if (isCutOffSplitter(mark.boneMark)) { 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)); m_cutoffErrorItems.push_back(SkeletonSideToDispName(mark.boneSide) + " " + BoneMarkToDispName(mark.boneMark));
return false; return false;
} }

View File

@ -27,13 +27,14 @@ public:
{ {
return m_isFirstBiggerThenSecond ? m_secondGroup : m_firstGroup; return m_isFirstBiggerThenSecond ? m_secondGroup : m_firstGroup;
} }
bool split(const std::vector<QVector3D> &verticesPositions, const std::set<MeshSplitterTriangle> &input, int expandRound=0) bool split(const std::vector<QVector3D> &verticesPositions, const std::set<MeshSplitterTriangle> &input,
const std::vector<std::pair<std::pair<size_t, size_t>, std::pair<size_t, size_t>>> &triangleLinks, int expandRound=0)
{ {
int totalRound = 1 + expandRound; int totalRound = 1 + expandRound;
for (int round = 0; round < totalRound; ++round) { for (int round = 0; round < totalRound; ++round) {
m_firstGroup.clear(); m_firstGroup.clear();
m_secondGroup.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) { if (splitResult) {
sortByDistanceFromOrigin(verticesPositions); sortByDistanceFromOrigin(verticesPositions);
return true; return true;
@ -125,7 +126,8 @@ class Rigger : public QObject
Q_OBJECT Q_OBJECT
public: public:
Rigger(const std::vector<QVector3D> &verticesPositions, Rigger(const std::vector<QVector3D> &verticesPositions,
const std::set<MeshSplitterTriangle> &inputTriangles); const std::set<MeshSplitterTriangle> &inputTriangles,
const std::vector<std::pair<std::pair<size_t, size_t>, std::pair<size_t, size_t>>> &triangleLinks);
bool addMarkGroup(BoneMark boneMark, SkeletonSide boneSide, QVector3D bonePosition, float nodeRadius, const std::set<MeshSplitterTriangle> &markTriangles); bool addMarkGroup(BoneMark boneMark, SkeletonSide boneSide, QVector3D bonePosition, float nodeRadius, const std::set<MeshSplitterTriangle> &markTriangles);
const std::vector<std::pair<QtMsgType, QString>> &messages(); const std::vector<std::pair<QtMsgType, QString>> &messages();
const std::vector<RiggerBone> &resultBones(); const std::vector<RiggerBone> &resultBones();
@ -155,6 +157,7 @@ protected:
std::vector<std::pair<QtMsgType, QString>> m_messages; std::vector<std::pair<QtMsgType, QString>> m_messages;
std::vector<QVector3D> m_verticesPositions; std::vector<QVector3D> m_verticesPositions;
std::set<MeshSplitterTriangle> m_inputTriangles; std::set<MeshSplitterTriangle> m_inputTriangles;
std::vector<std::pair<std::pair<size_t, size_t>, std::pair<size_t, size_t>>> m_triangleLinks;
std::vector<RiggerMark> m_marks; std::vector<RiggerMark> m_marks;
std::map<std::pair<BoneMark, SkeletonSide>, std::vector<int>> m_marksMap; std::map<std::pair<BoneMark, SkeletonSide>, std::vector<int>> m_marksMap;
std::vector<RiggerBone> m_resultBones; std::vector<RiggerBone> m_resultBones;

View File

@ -2,9 +2,10 @@
#include "animalrigger.h" #include "animalrigger.h"
Rigger *newRigger(RigType rigType, const std::vector<QVector3D> &verticesPositions, Rigger *newRigger(RigType rigType, const std::vector<QVector3D> &verticesPositions,
const std::set<MeshSplitterTriangle> &inputTriangles) const std::set<MeshSplitterTriangle> &inputTriangles,
const std::vector<std::pair<std::pair<size_t, size_t>, std::pair<size_t, size_t>>> &triangleLinks)
{ {
if (rigType == RigType::Animal) if (rigType == RigType::Animal)
return new AnimalRigger(verticesPositions, inputTriangles); return new AnimalRigger(verticesPositions, inputTriangles, triangleLinks);
return nullptr; return nullptr;
} }

View File

@ -5,6 +5,7 @@
#include "poser.h" #include "poser.h"
Rigger *newRigger(RigType rigType, const std::vector<QVector3D> &verticesPositions, Rigger *newRigger(RigType rigType, const std::vector<QVector3D> &verticesPositions,
const std::set<MeshSplitterTriangle> &inputTriangles); const std::set<MeshSplitterTriangle> &inputTriangles,
const std::vector<std::pair<std::pair<size_t, size_t>, std::pair<size_t, size_t>>> &triangleLinks);
#endif #endif

View File

@ -140,31 +140,30 @@ static bool fetchCgalMeshCenter(CgalMesh *cgalMesh, QVector3D &center)
return true; return true;
} }
static size_t findNearestTriangle(const Outcome &outcome, static std::pair<size_t, size_t> findNearestTriangleEdge(const Outcome &outcome,
const std::vector<size_t> &group, const std::vector<size_t> &group,
const QVector3D &point) const QVector3D &point)
{ {
float minLength2 = std::numeric_limits<float>::max(); float minLength2 = std::numeric_limits<float>::max();
size_t choosenIndex = 0; std::pair<size_t, size_t> choosenEdge = std::make_pair(0, 0);
for (const auto &triangleIndex: group) { for (const auto &triangleIndex: group) {
QVector3D sumOfPositions;
const auto &indices = outcome.triangles[triangleIndex]; const auto &indices = outcome.triangles[triangleIndex];
for (const auto &it: indices) { for (size_t i = 0; i < indices.size(); ++i) {
sumOfPositions += outcome.vertices[it]; size_t j = (i + 1) % indices.size();
} QVector3D edgeMiddle = (outcome.vertices[indices[i]] + outcome.vertices[indices[j]]) / 2;
QVector3D triangleCenter = sumOfPositions / indices.size(); float length2 = (point - edgeMiddle).lengthSquared();
float length2 = (point - triangleCenter).lengthSquared(); if (length2 < minLength2) {
if (length2 < minLength2) { minLength2 = length2;
minLength2 = length2; choosenEdge = std::make_pair(indices[i], indices[j]);
choosenIndex = triangleIndex; }
} }
} }
return choosenIndex; return choosenEdge;
} }
static bool mergeIntersectedConvexMeshesAndLinkTriangles(const Outcome &outcome, static bool mergeIntersectedConvexMeshesAndLinkTriangles(const Outcome &outcome,
std::map<QString, std::pair<CgalMesh *, std::vector<size_t>>> &convexMeshes, std::map<QString, std::pair<CgalMesh *, std::vector<size_t>>> &convexMeshes,
std::vector<std::pair<size_t, size_t>> &links) std::vector<std::pair<std::pair<size_t, size_t>, std::pair<size_t, size_t>>> &links)
{ {
if (convexMeshes.size() <= 1) if (convexMeshes.size() <= 1)
return false; return false;
@ -181,8 +180,8 @@ static bool mergeIntersectedConvexMeshesAndLinkTriangles(const Outcome &outcome,
QString secondGroupName = it.first; QString secondGroupName = it.first;
std::vector<size_t> firstGroupTriangleIndices = head.second.second; std::vector<size_t> firstGroupTriangleIndices = head.second.second;
std::vector<size_t> secondGroupTriangleIndices = it.second.second; std::vector<size_t> secondGroupTriangleIndices = it.second.second;
size_t firstGroupChoosenIndex = findNearestTriangle(outcome, firstGroupTriangleIndices, center); std::pair<size_t, size_t> firstGroupChoosenIndex = findNearestTriangleEdge(outcome, firstGroupTriangleIndices, center);
size_t secondGroupChoosenIndex = findNearestTriangle(outcome, secondGroupTriangleIndices, center); std::pair<size_t, size_t> secondGroupChoosenIndex = findNearestTriangleEdge(outcome, secondGroupTriangleIndices, center);
links.push_back(std::make_pair(firstGroupChoosenIndex, secondGroupChoosenIndex)); links.push_back(std::make_pair(firstGroupChoosenIndex, secondGroupChoosenIndex));
std::vector<size_t> triangleIndices(firstGroupTriangleIndices); std::vector<size_t> triangleIndices(firstGroupTriangleIndices);
triangleIndices.insert(triangleIndices.end(), secondGroupTriangleIndices.begin(), secondGroupTriangleIndices.end()); triangleIndices.insert(triangleIndices.end(), secondGroupTriangleIndices.begin(), secondGroupTriangleIndices.end());
@ -201,7 +200,7 @@ static bool mergeIntersectedConvexMeshesAndLinkTriangles(const Outcome &outcome,
} }
void triangleIslandsLink(const Outcome &outcome, void triangleIslandsLink(const Outcome &outcome,
std::vector<std::pair<size_t, size_t>> &links) std::vector<std::pair<std::pair<size_t, size_t>, std::pair<size_t, size_t>>> &links)
{ {
std::vector<size_t> group; std::vector<size_t> group;
std::vector<std::vector<size_t>> islands; std::vector<std::vector<size_t>> islands;

View File

@ -4,6 +4,6 @@
#include "outcome.h" #include "outcome.h"
void triangleIslandsLink(const Outcome &outcome, void triangleIslandsLink(const Outcome &outcome,
std::vector<std::pair<size_t, size_t>> &links); std::vector<std::pair<std::pair<size_t, size_t>, std::pair<size_t, size_t>>> &links);
#endif #endif