Use MeshState in MeshGenerator

master
Jeremy HU 2022-11-01 20:53:02 +11:00
parent 9fe28f84df
commit 1fa1e0e199
4 changed files with 69 additions and 92 deletions

View File

@ -103,24 +103,6 @@ void MeshGenerator::subdivideFace(std::vector<Vector2>* face)
}
}
bool MeshGenerator::isWatertight(const std::vector<std::vector<size_t>>& faces)
{
std::set<std::pair<size_t, size_t>> halfEdges;
for (const auto& face : faces) {
for (size_t i = 0; i < face.size(); ++i) {
size_t j = (i + 1) % face.size();
auto insertResult = halfEdges.insert({ face[i], face[j] });
if (!insertResult.second)
return false;
}
}
for (const auto& it : halfEdges) {
if (halfEdges.find({ it.second, it.first }) == halfEdges.end())
return false;
}
return true;
}
void MeshGenerator::recoverQuads(const std::vector<Vector3>& vertices, const std::vector<std::vector<size_t>>& triangles, const std::set<std::pair<PositionKey, PositionKey>>& sharedQuadEdges, std::vector<std::vector<size_t>>& triangleAndQuads)
{
std::vector<PositionKey> verticesPositionKeys;
@ -439,7 +421,7 @@ bool MeshGenerator::fetchPartOrderedNodes(const std::string& partIdString, std::
builderNodeIdStringToIndexMap.insert({ nodeIdString, builderNodes.size() });
builderNodes.emplace_back(MeshNode {
Vector3((double)x, (double)y, (double)z), (double)radius });
Vector3((double)x, (double)y, (double)z), (double)radius, Uuid(nodeIdString) });
}
if (builderNodes.empty()) {
@ -480,7 +462,7 @@ bool MeshGenerator::fetchPartOrderedNodes(const std::string& partIdString, std::
return true;
}
std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineStitchingMesh(const std::vector<std::string>& partIdStrings,
std::unique_ptr<MeshState> MeshGenerator::combineStitchingMesh(const std::vector<std::string>& partIdStrings,
const std::vector<std::string>& componentIdStrings,
GeneratedComponent& componentCache)
{
@ -511,7 +493,7 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineStitchingMesh(const st
stitchMeshBuilder->generatedFaces(),
&componentCache.sharedQuadEdges);
auto mesh = std::make_unique<MeshCombiner::Mesh>(stitchMeshBuilder->generatedVertices(),
auto mesh = std::make_unique<MeshState>(stitchMeshBuilder->generatedVertices(),
stitchMeshBuilder->generatedFaces());
if (mesh && mesh->isNull())
mesh.reset();
@ -563,7 +545,7 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineStitchingMesh(const st
return mesh;
}
std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combinePartMesh(const std::string& partIdString,
std::unique_ptr<MeshState> MeshGenerator::combinePartMesh(const std::string& partIdString,
const std::string& componentIdString,
bool* hasError)
{
@ -704,9 +686,9 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combinePartMesh(const std::st
}
bool hasMeshError = false;
std::unique_ptr<MeshCombiner::Mesh> mesh;
std::unique_ptr<MeshState> mesh;
mesh = std::make_unique<MeshCombiner::Mesh>(partCache.vertices, partCache.faces);
mesh = std::make_unique<MeshState>(partCache.vertices, partCache.faces);
if (mesh->isNull()) {
hasMeshError = true;
}
@ -800,9 +782,9 @@ std::string MeshGenerator::componentColorName(const std::map<std::string, std::s
return std::string();
}
std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineComponentMesh(const std::string& componentIdString, CombineMode* combineMode)
std::unique_ptr<MeshState> MeshGenerator::combineComponentMesh(const std::string& componentIdString, CombineMode* combineMode)
{
std::unique_ptr<MeshCombiner::Mesh> mesh;
std::unique_ptr<MeshState> mesh;
Uuid componentId;
const std::map<std::string, std::string>* component = &m_snapshot->rootComponent;
@ -822,7 +804,7 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineComponentMesh(const st
if (m_cacheEnabled) {
if (m_dirtyComponentIds.find(componentIdString) == m_dirtyComponentIds.end()) {
if (nullptr != componentCache.mesh)
return std::make_unique<MeshCombiner::Mesh>(*componentCache.mesh);
return std::make_unique<MeshState>(*componentCache.mesh);
}
}
@ -887,7 +869,7 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineComponentMesh(const st
}
combineGroups[currentGroupIndex].second.push_back(childIdString);
}
std::vector<std::tuple<std::unique_ptr<MeshCombiner::Mesh>, CombineMode, std::string>> groupMeshes;
std::vector<std::tuple<std::unique_ptr<MeshState>, CombineMode, std::string>> groupMeshes;
for (const auto& group : combineGroups) {
auto childMesh = combineComponentChildGroupMesh(group.second, componentCache);
if (nullptr == childMesh || childMesh->isNull())
@ -908,7 +890,7 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineComponentMesh(const st
}
if (nullptr != mesh)
componentCache.mesh = std::make_unique<MeshCombiner::Mesh>(*mesh);
componentCache.mesh = std::make_unique<MeshState>(*mesh);
if (nullptr != mesh && mesh->isNull()) {
mesh.reset();
@ -917,9 +899,9 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineComponentMesh(const st
return mesh;
}
std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineMultipleMeshes(std::vector<std::tuple<std::unique_ptr<MeshCombiner::Mesh>, CombineMode, std::string>>&& multipleMeshes)
std::unique_ptr<MeshState> MeshGenerator::combineMultipleMeshes(std::vector<std::tuple<std::unique_ptr<MeshState>, CombineMode, std::string>>&& multipleMeshes)
{
std::unique_ptr<MeshCombiner::Mesh> mesh;
std::unique_ptr<MeshState> mesh;
std::string meshIdStrings;
for (auto& it : multipleMeshes) {
auto subMesh = std::move(std::get<0>(it));
@ -936,20 +918,20 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineMultipleMeshes(std::ve
auto combinerMethod = childCombineMode == CombineMode::Inversion ? MeshCombiner::Method::Diff : MeshCombiner::Method::Union;
auto combinerMethodString = combinerMethod == MeshCombiner::Method::Union ? "+" : "-";
meshIdStrings += combinerMethodString + subMeshIdString;
std::unique_ptr<MeshCombiner::Mesh> newMesh;
std::unique_ptr<MeshState> newMesh;
auto findCached = m_cacheContext->cachedCombination.find(meshIdStrings);
if (findCached != m_cacheContext->cachedCombination.end()) {
if (nullptr != findCached->second.mesh) {
newMesh = std::make_unique<MeshCombiner::Mesh>(*findCached->second.mesh);
if (nullptr != findCached->second) {
newMesh = std::make_unique<MeshState>(*findCached->second);
}
} else {
newMesh = combineTwoMeshes(*mesh,
newMesh = MeshState::combine(*mesh,
*subMesh,
combinerMethod);
if (nullptr != newMesh)
m_cacheContext->cachedCombination.insert({ meshIdStrings, GeneratedCombination { std::make_unique<MeshCombiner::Mesh>(*newMesh) } });
m_cacheContext->cachedCombination.insert({ meshIdStrings, std::make_unique<MeshState>(*newMesh) });
else
m_cacheContext->cachedCombination.insert({ meshIdStrings, GeneratedCombination {} });
m_cacheContext->cachedCombination.insert({ meshIdStrings, nullptr });
}
if (newMesh && !newMesh->isNull()) {
mesh = std::move(newMesh);
@ -963,12 +945,12 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineMultipleMeshes(std::ve
return mesh;
}
std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineComponentChildGroupMesh(const std::vector<std::string>& componentIdStrings, GeneratedComponent& componentCache)
std::unique_ptr<MeshState> MeshGenerator::combineComponentChildGroupMesh(const std::vector<std::string>& componentIdStrings, GeneratedComponent& componentCache)
{
std::vector<std::tuple<std::unique_ptr<MeshCombiner::Mesh>, CombineMode, std::string>> multipleMeshes;
std::vector<std::tuple<std::unique_ptr<MeshState>, CombineMode, std::string>> multipleMeshes;
for (const auto& childIdString : componentIdStrings) {
CombineMode childCombineMode = CombineMode::Normal;
std::unique_ptr<MeshCombiner::Mesh> subMesh = combineComponentMesh(childIdString, &childCombineMode);
std::unique_ptr<MeshState> subMesh = combineComponentMesh(childIdString, &childCombineMode);
if (CombineMode::Uncombined == childCombineMode) {
continue;
@ -999,40 +981,6 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineComponentChildGroupMes
return combineMultipleMeshes(std::move(multipleMeshes));
}
std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineTwoMeshes(const MeshCombiner::Mesh& first, const MeshCombiner::Mesh& second,
MeshCombiner::Method method)
{
if (first.isNull() || second.isNull())
return nullptr;
std::vector<std::pair<MeshCombiner::Source, size_t>> combinedVerticesSources;
auto newMesh = std::unique_ptr<MeshCombiner::Mesh>(MeshCombiner::combine(first,
second,
method,
&combinedVerticesSources));
if (nullptr == newMesh)
return nullptr;
if (!newMesh->isNull()) {
MeshRecombiner recombiner;
std::vector<Vector3> combinedVertices;
std::vector<std::vector<size_t>> combinedFaces;
newMesh->fetch(combinedVertices, combinedFaces);
recombiner.setVertices(&combinedVertices, &combinedVerticesSources);
recombiner.setFaces(&combinedFaces);
if (recombiner.recombine()) {
if (isWatertight(recombiner.regeneratedFaces())) {
auto reMesh = std::make_unique<MeshCombiner::Mesh>(recombiner.regeneratedVertices(), recombiner.regeneratedFaces());
if (!reMesh->isNull()) {
newMesh = std::move(reMesh);
}
}
}
}
if (newMesh->isNull()) {
return nullptr;
}
return newMesh;
}
void MeshGenerator::makeXmirror(const std::vector<Vector3>& sourceVertices, const std::vector<std::vector<size_t>>& sourceFaces,
std::vector<Vector3>* destVertices, std::vector<std::vector<size_t>>* destFaces)
{
@ -1135,7 +1083,7 @@ void MeshGenerator::postprocessObject(Object* object)
object->setTriangleVertexNormals(triangleVertexNormals);
}
void MeshGenerator::collectIncombinableMesh(const MeshCombiner::Mesh* mesh, const GeneratedComponent& componentCache)
void MeshGenerator::collectIncombinableMesh(const MeshState* mesh, const GeneratedComponent& componentCache)
{
if (nullptr == mesh)
return;

View File

@ -30,6 +30,7 @@
#include <dust3d/base/uuid.h>
#include <dust3d/mesh/mesh_combiner.h>
#include <dust3d/mesh/mesh_node.h>
#include <dust3d/mesh/mesh_state.h>
#include <set>
#include <tuple>
#include <unordered_map>
@ -70,7 +71,7 @@ public:
};
struct GeneratedComponent {
std::unique_ptr<MeshCombiner::Mesh> mesh;
std::unique_ptr<MeshState> mesh;
std::set<std::pair<PositionKey, PositionKey>> sharedQuadEdges;
std::unordered_map<Uuid, std::map<std::array<PositionKey, 3>, std::array<Vector2, 3>>> partTriangleUvs;
std::vector<std::map<std::array<PositionKey, 3>, std::array<Vector2, 3>>> seamTriangleUvs;
@ -91,16 +92,11 @@ public:
}
};
struct GeneratedCombination {
std::unique_ptr<MeshCombiner::Mesh> mesh;
std::vector<std::map<std::array<PositionKey, 3>, std::array<Vector2, 3>>> seamTriangleUvs;
};
struct GeneratedCacheContext {
std::map<std::string, GeneratedComponent> components;
std::map<std::string, GeneratedPart> parts;
std::map<std::string, std::string> partMirrorIdMap;
std::map<std::string, GeneratedCombination> cachedCombination;
std::map<std::string, std::unique_ptr<MeshState>> cachedCombination;
};
struct ComponentPreview {
@ -151,27 +147,25 @@ private:
bool m_weldEnabled = true;
void collectParts();
void collectIncombinableMesh(const MeshCombiner::Mesh* mesh, const GeneratedComponent& componentCache);
void collectIncombinableMesh(const MeshState* mesh, const GeneratedComponent& componentCache);
bool checkIsComponentDirty(const std::string& componentIdString);
bool checkIsPartDirty(const std::string& partIdString);
bool checkIsPartDependencyDirty(const std::string& partIdString);
void checkDirtyFlags();
std::unique_ptr<MeshCombiner::Mesh> combinePartMesh(const std::string& partIdString,
std::unique_ptr<MeshState> combinePartMesh(const std::string& partIdString,
const std::string& componentIdString,
bool* hasError);
std::unique_ptr<MeshCombiner::Mesh> combineComponentMesh(const std::string& componentIdString, CombineMode* combineMode);
std::unique_ptr<MeshState> combineComponentMesh(const std::string& componentIdString, CombineMode* combineMode);
void makeXmirror(const std::vector<Vector3>& sourceVertices, const std::vector<std::vector<size_t>>& sourceFaces,
std::vector<Vector3>* destVertices, std::vector<std::vector<size_t>>* destFaces);
void collectSharedQuadEdges(const std::vector<Vector3>& vertices, const std::vector<std::vector<size_t>>& faces,
std::set<std::pair<PositionKey, PositionKey>>* sharedQuadEdges);
std::unique_ptr<MeshCombiner::Mesh> combineTwoMeshes(const MeshCombiner::Mesh& first, const MeshCombiner::Mesh& second,
MeshCombiner::Method method);
const std::map<std::string, std::string>* findComponent(const std::string& componentIdString);
CombineMode componentCombineMode(const std::map<std::string, std::string>* component);
std::unique_ptr<MeshCombiner::Mesh> combineComponentChildGroupMesh(const std::vector<std::string>& componentIdStrings,
std::unique_ptr<MeshState> combineComponentChildGroupMesh(const std::vector<std::string>& componentIdStrings,
GeneratedComponent& componentCache);
std::unique_ptr<MeshCombiner::Mesh> combineMultipleMeshes(std::vector<std::tuple<std::unique_ptr<MeshCombiner::Mesh>, CombineMode, std::string>>&& multipleMeshes);
std::unique_ptr<MeshCombiner::Mesh> combineStitchingMesh(const std::vector<std::string>& partIdStrings,
std::unique_ptr<MeshState> combineMultipleMeshes(std::vector<std::tuple<std::unique_ptr<MeshState>, CombineMode, std::string>>&& multipleMeshes);
std::unique_ptr<MeshState> combineStitchingMesh(const std::vector<std::string>& partIdStrings,
const std::vector<std::string>& componentIdStrings,
GeneratedComponent& componentCache);
std::string componentColorName(const std::map<std::string, std::string>* component);
@ -187,7 +181,6 @@ private:
static void chamferFace(std::vector<Vector2>* face);
static void subdivideFace(std::vector<Vector2>* face);
static bool isWatertight(const std::vector<std::vector<size_t>>& faces);
static void flattenLinks(const std::unordered_map<size_t, size_t>& links,
std::vector<size_t>* array,
bool* isCircle);

View File

@ -25,17 +25,37 @@
namespace dust3d {
MeshState::MeshState(const std::vector<Vector3>& vertices, const std::vector<std::vector<size_t>>& faces)
{
mesh = std::make_unique<MeshCombiner::Mesh>(vertices, faces);
}
MeshState::MeshState(const MeshState& other)
{
if (nullptr != other.mesh)
mesh = std::make_unique<MeshCombiner::Mesh>(*other.mesh);
seamTriangleUvs = other.seamTriangleUvs;
}
void MeshState::fetch(std::vector<Vector3>& vertices, std::vector<std::vector<size_t>>& faces) const
{
if (mesh)
mesh->fetch(vertices, faces);
}
bool MeshState::isNull() const
{
if (nullptr == mesh)
return true;
return mesh->isNull();
}
std::unique_ptr<MeshState> MeshState::combine(const MeshState& first, const MeshState& second,
MeshCombiner::Method method)
{
if (first.mesh->isNull() || second.mesh->isNull())
return nullptr;
auto newMeshState = std::make_unique<MeshState>();
std::vector<std::pair<MeshCombiner::Source, size_t>> combinedVerticesSources;
auto newMesh = std::unique_ptr<MeshCombiner::Mesh>(MeshCombiner::combine(*first.mesh,
*second.mesh,
@ -54,6 +74,19 @@ std::unique_ptr<MeshState> MeshState::combine(const MeshState& first, const Mesh
if (MeshState::isWatertight(recombiner.regeneratedFaces())) {
auto reMesh = std::make_unique<MeshCombiner::Mesh>(recombiner.regeneratedVertices(), recombiner.regeneratedFaces());
if (!reMesh->isNull()) {
for (const auto& uvSeams : recombiner.generatedBridgingTriangleUvs()) {
std::map<std::array<PositionKey, 3>, std::array<Vector2, 3>> uvs;
for (const auto& it : uvSeams) {
uvs.insert(std::make_pair(std::array<PositionKey, 3> {
PositionKey(it.first[0]),
PositionKey(it.first[1]),
PositionKey(it.first[2]) },
it.second));
}
if (uvs.empty())
continue;
newMeshState->seamTriangleUvs.push_back(uvs);
}
newMesh = std::move(reMesh);
}
}
@ -62,7 +95,6 @@ std::unique_ptr<MeshState> MeshState::combine(const MeshState& first, const Mesh
if (newMesh->isNull()) {
return nullptr;
}
auto newMeshState = std::make_unique<MeshState>();
newMeshState->mesh = std::move(newMesh);
return newMeshState;
}

View File

@ -34,7 +34,11 @@ public:
std::unique_ptr<MeshCombiner::Mesh> mesh;
std::vector<std::map<std::array<PositionKey, 3>, std::array<Vector2, 3>>> seamTriangleUvs;
MeshState() = default;
MeshState(const std::vector<Vector3>& vertices, const std::vector<std::vector<size_t>>& faces);
MeshState(const MeshState& other);
void fetch(std::vector<Vector3>& vertices, std::vector<std::vector<size_t>>& faces) const;
bool isNull() const;
static std::unique_ptr<MeshState> combine(const MeshState& first, const MeshState& second,
MeshCombiner::Method method);
static bool isWatertight(const std::vector<std::vector<size_t>>& faces);