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"
AnimalRigger::AnimalRigger(const std::vector<QVector3D> &verticesPositions,
const std::set<MeshSplitterTriangle> &inputTriangles) :
Rigger(verticesPositions, inputTriangles)
const std::set<MeshSplitterTriangle> &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
public:
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:
bool validate() override;
bool isCutOffSplitter(BoneMark boneMark) override;

View File

@ -4,6 +4,7 @@
#include "meshsplitter.h"
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> &firstGroup,
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
if (expandSplitter) {
std::vector<MeshSplitterTriangle> expandedTriangles;
@ -29,15 +46,13 @@ bool MeshSplitter::split(const std::set<MeshSplitterTriangle> &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 (oppositeTriangle != edgeToTriangleMap.end()) {
if (splitter.find(oppositeTriangle->second) == splitter.end()) {
expandedTriangles.push_back(oppositeTriangle->second);
}
}
}
}
size_t addTriangles = 0;
for (const auto &triangle: expandedTriangles) {
auto insertResult = splitter.insert(triangle);
@ -61,7 +76,7 @@ bool MeshSplitter::split(const std::set<MeshSplitterTriangle> &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,14 +107,18 @@ bool MeshSplitter::split(const std::set<MeshSplitterTriangle> &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);
}
}
auto linkedTriangle = edgeToLinkedTriangleMap.find(oppositeEdge);
if (linkedTriangle != edgeToLinkedTriangleMap.end()) {
if (processedTriangles.find(linkedTriangle->second) == processedTriangles.end()) {
waitQueue.push(linkedTriangle->second);
}
}
}
}
// Now, the remains should be put in the second group

View File

@ -1,6 +1,7 @@
#ifndef DUST3D_MESH_SPLITTER_H
#define DUST3D_MESH_SPLITTER_H
#include <set>
#include <vector>
class MeshSplitterTriangle
{
@ -18,6 +19,7 @@ class MeshSplitter
{
public:
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> &firstGroup,
std::set<MeshSplitterTriangle> &secondGroup,

View File

@ -124,6 +124,18 @@ public:
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:
bool m_hasTriangleSourceNodes = false;
std::vector<std::pair<QUuid, QUuid>> m_triangleSourceNodes;
@ -139,6 +151,9 @@ private:
bool m_hasPartUvRects = false;
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

View File

@ -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<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) {
qDebug() << "Unsupported rig type:" << RigTypeToString(m_rigType);
} else {

View File

@ -10,9 +10,11 @@ QString Rigger::rootBoneName = "Body";
//QString Rigger::firstSpineBoneName = "Spine1";
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_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;
}

View File

@ -27,13 +27,14 @@ public:
{
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;
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<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);
const std::vector<std::pair<QtMsgType, QString>> &messages();
const std::vector<RiggerBone> &resultBones();
@ -155,6 +157,7 @@ protected:
std::vector<std::pair<QtMsgType, QString>> m_messages;
std::vector<QVector3D> m_verticesPositions;
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::map<std::pair<BoneMark, SkeletonSide>, std::vector<int>> m_marksMap;
std::vector<RiggerBone> m_resultBones;

View File

@ -2,9 +2,10 @@
#include "animalrigger.h"
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)
return new AnimalRigger(verticesPositions, inputTriangles);
return new AnimalRigger(verticesPositions, inputTriangles, triangleLinks);
return nullptr;
}

View File

@ -5,6 +5,7 @@
#include "poser.h"
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

View File

@ -140,31 +140,30 @@ static bool fetchCgalMeshCenter(CgalMesh *cgalMesh, QVector3D &center)
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 QVector3D &point)
{
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) {
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();
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;
choosenIndex = triangleIndex;
choosenEdge = std::make_pair(indices[i], indices[j]);
}
}
return choosenIndex;
}
return choosenEdge;
}
static bool mergeIntersectedConvexMeshesAndLinkTriangles(const Outcome &outcome,
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)
return false;
@ -181,8 +180,8 @@ static bool mergeIntersectedConvexMeshesAndLinkTriangles(const Outcome &outcome,
QString secondGroupName = it.first;
std::vector<size_t> firstGroupTriangleIndices = head.second.second;
std::vector<size_t> secondGroupTriangleIndices = it.second.second;
size_t firstGroupChoosenIndex = findNearestTriangle(outcome, firstGroupTriangleIndices, center);
size_t secondGroupChoosenIndex = findNearestTriangle(outcome, secondGroupTriangleIndices, center);
std::pair<size_t, size_t> firstGroupChoosenIndex = findNearestTriangleEdge(outcome, firstGroupTriangleIndices, center);
std::pair<size_t, size_t> secondGroupChoosenIndex = findNearestTriangleEdge(outcome, secondGroupTriangleIndices, center);
links.push_back(std::make_pair(firstGroupChoosenIndex, secondGroupChoosenIndex));
std::vector<size_t> 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<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<std::vector<size_t>> islands;

View File

@ -4,6 +4,6 @@
#include "outcome.h"
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