Support rigging for uncombined mesh.
parent
00c05e8cb0
commit
74f5a081e3
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,12 +46,10 @@ 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 (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<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,12 +107,16 @@ 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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef DUST3D_MESH_SPLITTER_H
|
||||
#define DUST3D_MESH_SPLITTER_H
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
class MeshSplitterTriangle
|
||||
{
|
||||
|
@ -17,7 +18,8 @@ public:
|
|||
class MeshSplitter
|
||||
{
|
||||
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> &firstGroup,
|
||||
std::set<MeshSplitterTriangle> &secondGroup,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -140,31 +140,30 @@ static bool fetchCgalMeshCenter(CgalMesh *cgalMesh, QVector3D ¢er)
|
|||
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();
|
||||
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<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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue