Add mesh state
parent
7ce09d1cd6
commit
cb85a56364
|
@ -265,6 +265,8 @@ SOURCES += ../dust3d/mesh/mesh_generator.cc
|
|||
HEADERS += ../dust3d/mesh/mesh_node.h
|
||||
HEADERS += ../dust3d/mesh/mesh_recombiner.h
|
||||
SOURCES += ../dust3d/mesh/mesh_recombiner.cc
|
||||
HEADERS += ../dust3d/mesh/mesh_state.h
|
||||
SOURCES += ../dust3d/mesh/mesh_state.cc
|
||||
HEADERS += ../dust3d/mesh/re_triangulator.h
|
||||
SOURCES += ../dust3d/mesh/re_triangulator.cc
|
||||
HEADERS += ../dust3d/mesh/resolve_triangle_source_node.h
|
||||
|
|
|
@ -63,6 +63,7 @@ public:
|
|||
std::vector<std::vector<size_t>> triangleAndQuads;
|
||||
std::vector<std::vector<size_t>> triangles;
|
||||
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;
|
||||
std::vector<Vector3> triangleNormals;
|
||||
std::vector<Color> triangleColors;
|
||||
bool alphaEnabled = false;
|
||||
|
|
|
@ -900,7 +900,7 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineComponentMesh(const st
|
|||
groupMeshes.emplace_back(std::make_tuple(std::move(stitchingMesh), CombineMode::Normal, String::join(stitchingComponents, ":")));
|
||||
}
|
||||
}
|
||||
mesh = combineMultipleMeshes(std::move(groupMeshes), true);
|
||||
mesh = combineMultipleMeshes(std::move(groupMeshes));
|
||||
ComponentPreview preview;
|
||||
if (mesh)
|
||||
mesh->fetch(preview.vertices, preview.triangles);
|
||||
|
@ -917,7 +917,7 @@ 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, bool recombine)
|
||||
std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineMultipleMeshes(std::vector<std::tuple<std::unique_ptr<MeshCombiner::Mesh>, CombineMode, std::string>>&& multipleMeshes)
|
||||
{
|
||||
std::unique_ptr<MeshCombiner::Mesh> mesh;
|
||||
std::string meshIdStrings;
|
||||
|
@ -936,23 +936,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;
|
||||
if (recombine)
|
||||
meshIdStrings += "!";
|
||||
std::unique_ptr<MeshCombiner::Mesh> newMesh;
|
||||
auto findCached = m_cacheContext->cachedCombination.find(meshIdStrings);
|
||||
if (findCached != m_cacheContext->cachedCombination.end()) {
|
||||
if (nullptr != findCached->second) {
|
||||
newMesh = std::make_unique<MeshCombiner::Mesh>(*findCached->second);
|
||||
if (nullptr != findCached->second.mesh) {
|
||||
newMesh = std::make_unique<MeshCombiner::Mesh>(*findCached->second.mesh);
|
||||
}
|
||||
} else {
|
||||
newMesh = combineTwoMeshes(*mesh,
|
||||
*subMesh,
|
||||
combinerMethod,
|
||||
recombine);
|
||||
combinerMethod);
|
||||
if (nullptr != newMesh)
|
||||
m_cacheContext->cachedCombination.insert({ meshIdStrings, std::make_unique<MeshCombiner::Mesh>(*newMesh) });
|
||||
m_cacheContext->cachedCombination.insert({ meshIdStrings, GeneratedCombination { std::make_unique<MeshCombiner::Mesh>(*newMesh) } });
|
||||
else
|
||||
m_cacheContext->cachedCombination.insert({ meshIdStrings, nullptr });
|
||||
m_cacheContext->cachedCombination.insert({ meshIdStrings, GeneratedCombination {} });
|
||||
}
|
||||
if (newMesh && !newMesh->isNull()) {
|
||||
mesh = std::move(newMesh);
|
||||
|
@ -984,6 +981,8 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineComponentChildGroupMes
|
|||
componentCache.sharedQuadEdges.insert(it);
|
||||
for (const auto& it : childComponentCache.partTriangleUvs)
|
||||
componentCache.partTriangleUvs.insert({ it.first, it.second });
|
||||
for (const auto& it : childComponentCache.seamTriangleUvs)
|
||||
componentCache.seamTriangleUvs.push_back(it);
|
||||
for (const auto& it : childComponentCache.objectNodes)
|
||||
componentCache.objectNodes.push_back(it);
|
||||
for (const auto& it : childComponentCache.objectEdges)
|
||||
|
@ -1001,8 +1000,7 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineComponentChildGroupMes
|
|||
}
|
||||
|
||||
std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineTwoMeshes(const MeshCombiner::Mesh& first, const MeshCombiner::Mesh& second,
|
||||
MeshCombiner::Method method,
|
||||
bool recombine)
|
||||
MeshCombiner::Method method)
|
||||
{
|
||||
if (first.isNull() || second.isNull())
|
||||
return nullptr;
|
||||
|
@ -1013,7 +1011,7 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineTwoMeshes(const MeshCo
|
|||
&combinedVerticesSources));
|
||||
if (nullptr == newMesh)
|
||||
return nullptr;
|
||||
if (!newMesh->isNull() && recombine) {
|
||||
if (!newMesh->isNull()) {
|
||||
MeshRecombiner recombiner;
|
||||
std::vector<Vector3> combinedVertices;
|
||||
std::vector<std::vector<size_t>> combinedFaces;
|
||||
|
@ -1352,6 +1350,7 @@ void MeshGenerator::generate()
|
|||
m_object->nodes = componentCache.objectNodes;
|
||||
m_object->edges = componentCache.objectEdges;
|
||||
m_object->partTriangleUvs = componentCache.partTriangleUvs;
|
||||
m_object->seamTriangleUvs = componentCache.seamTriangleUvs;
|
||||
m_nodeVertices = componentCache.objectNodeVertices;
|
||||
|
||||
std::vector<Vector3> combinedVertices;
|
||||
|
|
|
@ -73,6 +73,7 @@ public:
|
|||
std::unique_ptr<MeshCombiner::Mesh> 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;
|
||||
std::set<PositionKey> noneSeamVertices;
|
||||
std::vector<ObjectNode> objectNodes;
|
||||
std::vector<std::pair<std::pair<Uuid, Uuid>, std::pair<Uuid, Uuid>>> objectEdges;
|
||||
|
@ -82,6 +83,7 @@ public:
|
|||
mesh.reset();
|
||||
sharedQuadEdges.clear();
|
||||
partTriangleUvs.clear();
|
||||
seamTriangleUvs.clear();
|
||||
noneSeamVertices.clear();
|
||||
objectNodes.clear();
|
||||
objectEdges.clear();
|
||||
|
@ -89,11 +91,16 @@ 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, std::unique_ptr<MeshCombiner::Mesh>> cachedCombination;
|
||||
std::map<std::string, GeneratedCombination> cachedCombination;
|
||||
};
|
||||
|
||||
struct ComponentPreview {
|
||||
|
@ -158,13 +165,12 @@ private:
|
|||
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,
|
||||
bool recombine = true);
|
||||
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,
|
||||
GeneratedComponent& componentCache);
|
||||
std::unique_ptr<MeshCombiner::Mesh> combineMultipleMeshes(std::vector<std::tuple<std::unique_ptr<MeshCombiner::Mesh>, CombineMode, std::string>>&& multipleMeshes, bool recombine = true);
|
||||
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,
|
||||
const std::vector<std::string>& componentIdStrings,
|
||||
GeneratedComponent& componentCache);
|
||||
|
|
|
@ -149,7 +149,7 @@ bool MeshRecombiner::recombine()
|
|||
}
|
||||
}
|
||||
std::map<size_t, size_t> seamVertexToIslandMap;
|
||||
size_t islands = splitSeamVerticesToIslands(seamLink, &seamVertexToIslandMap);
|
||||
splitSeamVerticesToIslands(seamLink, &seamVertexToIslandMap);
|
||||
|
||||
std::map<std::pair<size_t, size_t>, std::pair<size_t, bool>> edgesInSeamArea;
|
||||
for (size_t faceIndex = 0; faceIndex < (*m_faces).size(); ++faceIndex) {
|
||||
|
@ -376,6 +376,22 @@ bool MeshRecombiner::bridge(const std::vector<size_t>& first, const std::vector<
|
|||
|
||||
void MeshRecombiner::fillPairs(const std::vector<size_t>& small, const std::vector<size_t>& large)
|
||||
{
|
||||
std::vector<std::pair<std::array<Vector3, 3>, std::array<Vector2, 3>>> bridgingFaceUvs;
|
||||
|
||||
std::vector<double> leftV(small.size(), 0.0);
|
||||
double leftOffset = 0.0;
|
||||
for (size_t j = 1; j < small.size(); ++j) {
|
||||
leftOffset += ((*m_vertices)[small[j]] - (*m_vertices)[small[j - 1]]).length();
|
||||
leftV[j] = leftOffset;
|
||||
}
|
||||
|
||||
std::vector<double> rightV(large.size(), 0.0);
|
||||
double rightOffset = 0.0;
|
||||
for (size_t j = 1; j < large.size(); ++j) {
|
||||
rightOffset += ((*m_vertices)[large[j]] - (*m_vertices)[large[j - 1]]).length();
|
||||
rightV[j] = rightOffset;
|
||||
}
|
||||
|
||||
size_t smallIndex = 0;
|
||||
size_t largeIndex = 0;
|
||||
while (smallIndex + 1 < small.size() || largeIndex + 1 < large.size()) {
|
||||
|
@ -388,12 +404,18 @@ void MeshRecombiner::fillPairs(const std::vector<size_t>& small, const std::vect
|
|||
m_regeneratedFaces.push_back({ small[smallIndex],
|
||||
small[smallIndex + 1],
|
||||
large[largeIndex] });
|
||||
bridgingFaceUvs.emplace_back(std::make_pair(
|
||||
std::array<Vector3, 3> { (*m_vertices)[small[smallIndex]], (*m_vertices)[small[smallIndex + 1]], (*m_vertices)[large[largeIndex]] },
|
||||
std::array<Vector2, 3> { Vector2(0.0, leftV[smallIndex]), Vector2(0.0, leftV[smallIndex + 1]), Vector2(1.0, rightV[largeIndex]) }));
|
||||
++smallIndex;
|
||||
continue;
|
||||
}
|
||||
m_regeneratedFaces.push_back({ large[largeIndex + 1],
|
||||
large[largeIndex],
|
||||
small[smallIndex] });
|
||||
bridgingFaceUvs.emplace_back(std::make_pair(
|
||||
std::array<Vector3, 3> { (*m_vertices)[large[largeIndex + 1]], (*m_vertices)[large[largeIndex]], (*m_vertices)[small[smallIndex]] },
|
||||
std::array<Vector2, 3> { Vector2(1.0, rightV[largeIndex + 1]), Vector2(1.0, rightV[largeIndex]), Vector2(0.0, rightV[largeIndex]) }));
|
||||
++largeIndex;
|
||||
continue;
|
||||
}
|
||||
|
@ -401,6 +423,9 @@ void MeshRecombiner::fillPairs(const std::vector<size_t>& small, const std::vect
|
|||
m_regeneratedFaces.push_back({ large[largeIndex + 1],
|
||||
large[largeIndex],
|
||||
small[smallIndex] });
|
||||
bridgingFaceUvs.emplace_back(std::make_pair(
|
||||
std::array<Vector3, 3> { (*m_vertices)[large[largeIndex + 1]], (*m_vertices)[large[largeIndex]], (*m_vertices)[small[smallIndex]] },
|
||||
std::array<Vector2, 3> { Vector2(1.0, rightV[largeIndex + 1]), Vector2(1.0, rightV[largeIndex]), Vector2(0.0, rightV[largeIndex]) }));
|
||||
++largeIndex;
|
||||
continue;
|
||||
}
|
||||
|
@ -408,11 +433,16 @@ void MeshRecombiner::fillPairs(const std::vector<size_t>& small, const std::vect
|
|||
m_regeneratedFaces.push_back({ small[smallIndex],
|
||||
small[smallIndex + 1],
|
||||
large[largeIndex] });
|
||||
bridgingFaceUvs.emplace_back(std::make_pair(
|
||||
std::array<Vector3, 3> { (*m_vertices)[small[smallIndex]], (*m_vertices)[small[smallIndex + 1]], (*m_vertices)[large[largeIndex]] },
|
||||
std::array<Vector2, 3> { Vector2(0.0, leftV[smallIndex]), Vector2(0.0, leftV[smallIndex + 1]), Vector2(1.0, rightV[largeIndex]) }));
|
||||
++smallIndex;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
m_generatedBridgingTriangleUvs.emplace_back(bridgingFaceUvs);
|
||||
}
|
||||
|
||||
void MeshRecombiner::removeReluctantVertices()
|
||||
|
@ -438,4 +468,9 @@ void MeshRecombiner::removeReluctantVertices()
|
|||
m_regeneratedFaces = rearrangedFaces;
|
||||
}
|
||||
|
||||
const std::vector<std::vector<std::pair<std::array<Vector3, 3>, std::array<Vector2, 3>>>>& MeshRecombiner::generatedBridgingTriangleUvs()
|
||||
{
|
||||
return m_generatedBridgingTriangleUvs;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#ifndef DUST3D_MESH_MESH_RECOMBINER_H_
|
||||
#define DUST3D_MESH_MESH_RECOMBINER_H_
|
||||
|
||||
#include <dust3d/base/vector2.h>
|
||||
#include <dust3d/mesh/mesh_combiner.h>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
@ -38,6 +39,7 @@ public:
|
|||
const std::vector<Vector3>& regeneratedVertices();
|
||||
const std::vector<std::pair<MeshCombiner::Source, size_t>>& regeneratedVerticesSourceIndices();
|
||||
const std::vector<std::vector<size_t>>& regeneratedFaces();
|
||||
const std::vector<std::vector<std::pair<std::array<Vector3, 3>, std::array<Vector2, 3>>>>& generatedBridgingTriangleUvs();
|
||||
bool recombine();
|
||||
|
||||
private:
|
||||
|
@ -50,6 +52,7 @@ private:
|
|||
std::map<std::pair<size_t, size_t>, size_t> m_halfEdgeToFaceMap;
|
||||
std::map<size_t, size_t> m_facesInSeamArea;
|
||||
std::set<size_t> m_goodSeams;
|
||||
std::vector<std::vector<std::pair<std::array<Vector3, 3>, std::array<Vector2, 3>>>> m_generatedBridgingTriangleUvs;
|
||||
|
||||
bool addFaceToHalfEdgeToFaceMap(size_t faceIndex,
|
||||
std::map<std::pair<size_t, size_t>, size_t>& halfEdgeToFaceMap);
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2022 Jeremy HU <jeremy-at-dust3d dot org>. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <dust3d/mesh/mesh_state.h>
|
||||
|
||||
namespace dust3d {
|
||||
|
||||
void MeshState::fetch(std::vector<Vector3>& vertices, std::vector<std::vector<size_t>>& faces) const
|
||||
{
|
||||
if (mesh)
|
||||
mesh->fetch(vertices, faces);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2022 Jeremy HU <jeremy-at-dust3d dot org>. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef DUST3D_MESH_MESH_STATE_H_
|
||||
#define DUST3D_MESH_MESH_STATE_H_
|
||||
|
||||
#include <dust3d/base/position_key.h>
|
||||
#include <dust3d/mesh/mesh_combiner.h>
|
||||
#include <map>
|
||||
|
||||
namespace dust3d {
|
||||
|
||||
class MeshState {
|
||||
public:
|
||||
std::unique_ptr<MeshCombiner::Mesh> mesh;
|
||||
std::vector<std::map<std::array<PositionKey, 3>, std::array<Vector2, 3>>> seamTriangleUvs;
|
||||
|
||||
void fetch(std::vector<Vector3>& vertices, std::vector<std::vector<size_t>>& faces) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue