Skip to content

Commit

Permalink
Implement non-convex section remeshing
Browse files Browse the repository at this point in the history
  • Loading branch information
huxingyi committed Dec 21, 2022
1 parent fc71f69 commit f30490f
Show file tree
Hide file tree
Showing 2 changed files with 218 additions and 37 deletions.
243 changes: 209 additions & 34 deletions dust3d/mesh/section_remesher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
*/

#include <algorithm>
#include <dust3d/base/debug.h>
#include <dust3d/mesh/section_remesher.h>

namespace dust3d {
Expand All @@ -47,16 +48,30 @@ const std::vector<std::vector<Vector2>>& SectionRemesher::generatedFaceUvs()
return m_generatedFaceUvs;
}

bool SectionRemesher::isConvex(const std::vector<Vector3>& vertices)
Vector3 SectionRemesher::sectionNormal(const std::vector<size_t>& ringVertices)
{
if (vertices.size() <= 3)
if (ringVertices.size() < 3)
return Vector3();

Vector3 normal = Vector3::normal(m_vertices[ringVertices[1]], m_vertices[ringVertices[2]], m_vertices[ringVertices[0]]);
for (size_t i = 1; i < ringVertices.size(); ++i) {
size_t j = (i + 1) % ringVertices.size();
size_t k = (i + 2) % ringVertices.size();
normal += Vector3::normal(m_vertices[ringVertices[j]], m_vertices[ringVertices[k]], m_vertices[ringVertices[i]]);
}
return normal.normalized();
}

bool SectionRemesher::isConvex(const std::vector<size_t>& ringVertices)
{
if (ringVertices.size() <= 3)
return true;

Vector3 previousNormal = Vector3::normal(vertices[0], vertices[1], vertices[2]);
for (size_t i = 1; i < vertices.size(); ++i) {
size_t j = (i + 1) % vertices.size();
size_t k = (i + 2) % vertices.size();
Vector3 currentNormal = Vector3::normal(vertices[i], vertices[j], vertices[k]);
Vector3 previousNormal = Vector3::normal(m_vertices[ringVertices[1]], m_vertices[ringVertices[2]], m_vertices[ringVertices[0]]);
for (size_t i = 1; i < ringVertices.size(); ++i) {
size_t j = (i + 1) % ringVertices.size();
size_t k = (i + 2) % ringVertices.size();
Vector3 currentNormal = Vector3::normal(m_vertices[ringVertices[j]], m_vertices[ringVertices[k]], m_vertices[ringVertices[i]]);
if (Vector3::dotProduct(previousNormal, currentNormal) < 0)
return false;
previousNormal = currentNormal;
Expand All @@ -65,39 +80,199 @@ bool SectionRemesher::isConvex(const std::vector<Vector3>& vertices)
return true;
}

void SectionRemesher::remesh()
void SectionRemesher::remeshConvex(const std::vector<size_t>& ringVertices, const std::vector<double>& ringUs)
{
m_ringSize = m_vertices.size();

if (isConvex(m_vertices)) {
Vector3 center;
for (const auto& it : m_vertices)
center += it;
center /= m_vertices.size();
m_vertices.push_back(center);
double offsetU = 0;
std::vector<double> maxUs(m_ringSize + 1);
for (size_t i = 0; i < m_ringSize; ++i) {
size_t j = (i + 1) % m_ringSize;
maxUs[i] = offsetU;
offsetU += (m_vertices[i] - m_vertices[j]).length();
Vector3 center;
for (const auto& it : ringVertices)
center += m_vertices[it];
center /= ringVertices.size();
size_t centerVertex = m_vertices.size();
m_vertices.push_back(center);

for (size_t i = 0; i < ringVertices.size(); ++i) {
size_t j = (i + 1) % ringVertices.size();
m_generatedFaces.emplace_back(std::vector<size_t> { ringVertices[i], ringVertices[j], centerVertex });
m_generatedFaceUvs.emplace_back(std::vector<Vector2> {
Vector2(ringUs[i], m_ringV),
Vector2(ringUs[i + 1], m_ringV),
Vector2((ringUs[i] + ringUs[i + 1]) * 0.5, m_centerV) });
}
}

int SectionRemesher::findNonConvexVertex(const std::vector<size_t>& ringVertices)
{
int nonConvexVertex = -1;
double maxEdgeLength = 0.0;
Vector3 positiveNormal = sectionNormal(ringVertices);
for (size_t i = 0; i < ringVertices.size(); ++i) {
size_t j = (i + 1) % ringVertices.size();
size_t k = (i + 2) % ringVertices.size();
Vector3 currentNormal = Vector3::normal(m_vertices[ringVertices[j]], m_vertices[ringVertices[k]], m_vertices[ringVertices[i]]);
if (Vector3::dotProduct(positiveNormal, currentNormal) >= 0)
continue;
double edgeLength = (m_vertices[ringVertices[j]] - m_vertices[ringVertices[k]]).length() + (m_vertices[ringVertices[j]] - m_vertices[ringVertices[i]]).length();
if (edgeLength > maxEdgeLength) {
maxEdgeLength = edgeLength;
nonConvexVertex = (int)j;
}
maxUs[m_ringSize] += offsetU;
offsetU = std::max(offsetU, std::numeric_limits<double>::epsilon());
for (auto& it : maxUs)
it /= offsetU;
for (size_t i = 0; i < m_ringSize; ++i) {
size_t j = (i + 1) % m_ringSize;
m_generatedFaces.emplace_back(std::vector<size_t> { i, j, m_ringSize });
m_generatedFaceUvs.emplace_back(std::vector<Vector2> {
Vector2(maxUs[i], m_ringV),
Vector2(maxUs[i + 1], m_ringV),
Vector2((maxUs[i] + maxUs[i + 1]) * 0.5, m_centerV) });
}
return nonConvexVertex;
}

int SectionRemesher::findPairVertex(const std::vector<size_t>& ringVertices, int vertex)
{
size_t halfSize = ringVertices.size() / 2;
size_t quarterSize = std::max(ringVertices.size() / 4, (size_t)2);
double maxDotProduct = std::numeric_limits<double>::lowest();
int pairVertex = -1;
Vector3 forwardDirection = ((m_vertices[ringVertices[vertex]] - m_vertices[ringVertices[(vertex + 1) % ringVertices.size()]]) + (m_vertices[ringVertices[vertex]] - m_vertices[ringVertices[(vertex + ringVertices.size() - 1) % ringVertices.size()]])).normalized();
for (size_t i = 0; i < halfSize; ++i) {
size_t index = (vertex + quarterSize + i) % ringVertices.size();
if ((int)index == vertex)
continue;
double dot = Vector3::dotProduct(forwardDirection, (m_vertices[ringVertices[index]] - m_vertices[ringVertices[vertex]]).normalized());
if (dot > maxDotProduct) {
maxDotProduct = dot;
pairVertex = index;
}
}
return pairVertex;
}

void SectionRemesher::remeshRing(const std::vector<size_t>& ringVertices, const std::vector<double>& ringUs)
{
if (isConvex(ringVertices)) {
remeshConvex(ringVertices, ringUs);
return;
}
int nonConvexVertex = findNonConvexVertex(ringVertices);
if (-1 == nonConvexVertex) {
remeshConvex(ringVertices, ringUs);
return;
}
int pairVertex = findPairVertex(ringVertices, nonConvexVertex);
if (-1 == pairVertex) {
remeshConvex(ringVertices, ringUs);
return;
}

auto nextVertex = [&](int index) {
return (index + 1) % ringVertices.size();
};

std::vector<size_t> leftRing;
std::vector<double> leftUs;
for (int i = pairVertex;; i = nextVertex(i)) {
leftRing.push_back(i);
leftUs.push_back(ringUs[i]);
if (i == nonConvexVertex)
break;
}
leftUs.push_back(leftUs.back());
remeshRing(leftRing, leftUs);

std::vector<size_t> rightRing;
std::vector<double> rightUs;
for (int i = nonConvexVertex;; i = nextVertex(i)) {
rightRing.push_back(i);
rightUs.push_back(ringUs[i]);
if (i == pairVertex)
break;
}
rightUs.push_back(rightUs.back());
remeshRing(rightRing, rightUs);
}

void SectionRemesher::remesh()
{
m_ringUs.resize(m_vertices.size() + 1);
double offsetU = 0;
for (size_t i = 0; i < m_vertices.size(); ++i) {
size_t j = (i + 1) % m_vertices.size();
m_ringUs[i] = offsetU;
offsetU += (m_vertices[i] - m_vertices[j]).length();
}
m_ringUs[m_vertices.size()] += offsetU;
offsetU = std::max(offsetU, std::numeric_limits<double>::epsilon());
for (auto& it : m_ringUs)
it /= offsetU;

std::vector<size_t> ring(m_vertices.size());
for (size_t i = 0; i < ring.size(); ++i)
ring[i] = i;
remeshRing(ring, m_ringUs);
/*
int nonConvexVertex = -1;
if (isConvex(m_vertices) || -1 == (nonConvexVertex = findNonConvexVertex(m_vertices))) {
remeshConvex(m_vertices, m_ringUs);
return;
}
int pairVertex = findPairVertex(m_vertices, nonConvexVertex);
if (-1 == pairVertex) {
remeshConvex(m_vertices, m_ringUs);
return;
}
// TODO: Process non convex
auto nextVertex = [&](int index) {
return (index + 1) % m_vertices.size();
};
auto previousVertex = [&](int index) {
return (index + m_vertices.size() - 1) % m_vertices.size();
};
struct CutLine {
int nearVertex;
int farVertex;
};
std::vector<CutLine> cutLines;
for (int i = nonConvexVertex, j = pairVertex;;
i = previousVertex(i), j = nextVertex(j)) {
cutLines.push_back(CutLine { i, j });
if (i == j || i == nextVertex(j))
break;
}
std::reverse(cutLines.begin(), cutLines.end());
for (int i = nextVertex(nonConvexVertex), j = previousVertex(pairVertex);;
i = nextVertex(i), j = previousVertex(j)) {
cutLines.push_back(CutLine { i, j });
if (i == j || i == previousVertex(j))
break;
}
if (cutLines.size() < 2) {
remeshConvex(m_vertices, m_ringUs);
return;
}
dust3dDebug << "cutLines: (m_vertices:" << m_vertices.size() << ")";
for (size_t i = 0; i < cutLines.size(); ++i) {
dust3dDebug << "line[" << i << "]:" << cutLines[i].nearVertex << (cutLines[i].nearVertex == nonConvexVertex ? "(nonConv)" : "") << cutLines[i].farVertex << (cutLines[i].farVertex == pairVertex ? "(pair)" : "");
}
for (size_t j = 1; j < cutLines.size(); ++j) {
size_t i = j - 1;
if (cutLines[i].nearVertex == cutLines[i].farVertex) {
if (cutLines[i].nearVertex == cutLines[j].nearVertex || cutLines[i].farVertex == cutLines[j].farVertex)
continue;
dust3dDebug << "A" << cutLines[i].nearVertex << cutLines[j].nearVertex << cutLines[j].farVertex;
m_generatedFaces.emplace_back(std::vector<size_t> { cutLines[i].nearVertex, cutLines[j].nearVertex, cutLines[j].farVertex });
m_generatedFaceUvs.emplace_back(std::vector<Vector2> { Vector2(), Vector2(), Vector2() });
} else if (cutLines[j].nearVertex == cutLines[j].farVertex) {
if (cutLines[i].nearVertex == cutLines[j].nearVertex || cutLines[i].farVertex == cutLines[j].farVertex)
continue;
dust3dDebug << "B" << cutLines[i].nearVertex << cutLines[j].nearVertex << cutLines[i].farVertex;
m_generatedFaces.emplace_back(std::vector<size_t> { cutLines[i].nearVertex, cutLines[j].nearVertex, cutLines[i].farVertex });
m_generatedFaceUvs.emplace_back(std::vector<Vector2> { Vector2(), Vector2(), Vector2() });
} else {
dust3dDebug << "C" << cutLines[i].nearVertex << cutLines[j].nearVertex << cutLines[j].farVertex << cutLines[i].farVertex;
m_generatedFaces.emplace_back(std::vector<size_t> { cutLines[i].nearVertex, cutLines[j].nearVertex, cutLines[j].farVertex, cutLines[i].farVertex });
m_generatedFaceUvs.emplace_back(std::vector<Vector2> { Vector2(), Vector2(), Vector2(), Vector2() });
}
}
*/
}

}
12 changes: 9 additions & 3 deletions dust3d/mesh/section_remesher.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,17 @@ class SectionRemesher {
std::vector<std::vector<size_t>> m_generatedFaces;
std::vector<std::vector<Vector2>> m_generatedFaceUvs;

size_t m_ringSize = 0;
std::vector<Vector3> m_vertices;
double m_ringV = 0.0;
double m_centerV = 0.0;
std::vector<Vector3> m_vertices;
bool isConvex(const std::vector<Vector3>& vertices);
std::vector<double> m_ringUs;

void remeshConvex(const std::vector<size_t>& ringVertices, const std::vector<double>& ringUs);
Vector3 sectionNormal(const std::vector<size_t>& ringVertices);
int findNonConvexVertex(const std::vector<size_t>& ringVertices);
int findPairVertex(const std::vector<size_t>& ringVertices, int vertex);
void remeshRing(const std::vector<size_t>& ringVertices, const std::vector<double>& ringUs);
bool isConvex(const std::vector<size_t>& ringVertices);
};

}
Expand Down

0 comments on commit f30490f

Please sign in to comment.