diff --git a/examples/Prototype/ProgressiveMesh/GenericToPM/Main.cpp b/examples/Prototype/ProgressiveMesh/GenericToPM/Main.cpp index 47918322..9c695044 100644 --- a/examples/Prototype/ProgressiveMesh/GenericToPM/Main.cpp +++ b/examples/Prototype/ProgressiveMesh/GenericToPM/Main.cpp @@ -42,7 +42,6 @@ int main(int argc, char** argv) uint32_t polygonCount = mesh.GetPolygonCount(); std::vector indexBuffer; - indexBuffer.reserve(polygonCount); for (uint32_t polygonIndex = 0U; polygonIndex < polygonCount; ++polygonIndex) { const auto& polygon = mesh.GetPolygon(polygonIndex); @@ -54,10 +53,10 @@ int main(int argc, char** argv) } } - auto hem = cd::HalfEdgeMesh::FromIndexedMesh(mesh); - auto boundaryMesh = cd::Mesh::FromHalfEdgeMesh(hem, cd::ConvertStrategy::BoundaryOnly); + //auto hem = cd::HalfEdgeMesh::FromIndexedMesh(mesh); + //auto boundaryMesh = cd::Mesh::FromHalfEdgeMesh(hem, cd::ConvertStrategy::BoundaryOnly); auto pm = cd::ProgressiveMesh::FromIndexedMesh(mesh); - pm.InitBoundary(boundaryMesh); + //pm.InitBoundary(boundaryMesh); auto [permutation, map] = pm.BuildCollapseOperations(); } diff --git a/private/ProgressiveMesh/ProgressiveMeshImpl.cpp b/private/ProgressiveMesh/ProgressiveMeshImpl.cpp index c8a1c5b1..09e85deb 100644 --- a/private/ProgressiveMesh/ProgressiveMeshImpl.cpp +++ b/private/ProgressiveMesh/ProgressiveMeshImpl.cpp @@ -4,6 +4,7 @@ #include "Scene/Mesh.h" #include +#include namespace cd::pm { @@ -79,6 +80,12 @@ std::pair, std::vector> ProgressiveMeshImpl::Bui ComputeEdgeCollapseCostAtVertex(vertex.GetID()); } + for (auto& vertex : m_vertices) + { + assert(vertex.GetID().IsValid()); + m_minCostVertexQueue.insert(&vertex); + } + uint32_t vertexCount = GetVertexCount(); std::vector permutation; permutation.resize(vertexCount); @@ -88,12 +95,16 @@ std::pair, std::vector> ProgressiveMeshImpl::Bui for (int vertexIndex = static_cast(vertexCount) - 1; vertexIndex >= 0; --vertexIndex) { - Vertex* pCandidate = GetMinimumCostVertex(); + assert(!m_minCostVertexQueue.empty()); + auto itMinVertex = m_minCostVertexQueue.begin(); + Vertex* pCandidate = *itMinVertex; + m_minCostVertexQueue.erase(itMinVertex); + assert(pCandidate); permutation[pCandidate->GetID().Data()] = vertexIndex; map[vertexIndex] = pCandidate->GetCollapseTarget().Data(); - printf("Collapse2 [Vertex %d] - [Vertex %d]\n", pCandidate->GetID().Data(), pCandidate->GetCollapseTarget().Data()); + //printf("Collapse [Vertex %d] - [Vertex %d], cost = %f\n", pCandidate->GetID().Data(), pCandidate->GetCollapseTarget().Data(), pCandidate->GetCollapseCost()); Collapse(pCandidate->GetID(), pCandidate->GetCollapseTarget()); } @@ -314,11 +325,10 @@ float ProgressiveMeshImpl::ComputeEdgeCollapseCostAtEdge(VertexID v0ID, VertexID } float cost = edgeLength * curvature; - if (v0.IsOnBoundary()) - { - cost += 1.0f; - } - + //if (v0.IsOnBoundary()) + //{ + // cost += 1.0f; + //} return cost; } @@ -376,8 +386,11 @@ void ProgressiveMeshImpl::Collapse(VertexID v0ID, VertexID v1ID) for (auto vertexID : tmp) { + Vertex& v = GetVertex(vertexID.Data()); + m_minCostVertexQueue.erase(&v); //printf("\t2 ComputeEdgeCostAtVertex [%d]\n", vertexID.Data()); ComputeEdgeCollapseCostAtVertex(vertexID); + m_minCostVertexQueue.insert(&v); } } diff --git a/private/ProgressiveMesh/ProgressiveMeshImpl.h b/private/ProgressiveMesh/ProgressiveMeshImpl.h index e9f61ab9..4e002a44 100644 --- a/private/ProgressiveMesh/ProgressiveMeshImpl.h +++ b/private/ProgressiveMesh/ProgressiveMeshImpl.h @@ -4,7 +4,7 @@ #include "Vertex.h" #include "Scene/ObjectID.h" -#include +#include namespace cd { @@ -14,6 +14,19 @@ class Mesh; namespace pm { +struct CompareVertexCollapseCost +{ + bool operator()(const Vertex* pV0, const Vertex* pV1) const + { + float v0Cost = pV0->GetCollapseCost(); + float v1Cost = pV1->GetCollapseCost(); + //printf("Compare [Vertex %u] and [Vertex %u]\n", pV0->GetID().Data(), pV1->GetID().Data()); + //printf("\t[Vertex %u] cost is %f\n", pV0->GetID().Data(), v0Cost); + //printf("\t[Vertex %u] cost is %f\n", pV1->GetID().Data(), v1Cost); + return v0Cost == v1Cost ? pV0->GetID() < pV1->GetID() : v0Cost < v1Cost; + } +}; + class CORE_API ProgressiveMeshImpl { public: @@ -51,6 +64,7 @@ class CORE_API ProgressiveMeshImpl private: std::vector m_vertices; std::vector m_faces; + std::multiset m_minCostVertexQueue; }; } diff --git a/private/ProgressiveMesh/Vertex.cpp b/private/ProgressiveMesh/Vertex.cpp index b418a3c9..db87d253 100644 --- a/private/ProgressiveMesh/Vertex.cpp +++ b/private/ProgressiveMesh/Vertex.cpp @@ -19,4 +19,9 @@ void Vertex::AddAdjacentFace(FaceID faceID) } } +float Vertex::GetCollapseCost() const +{ + return m_collapseCost; +} + } \ No newline at end of file diff --git a/private/ProgressiveMesh/Vertex.h b/private/ProgressiveMesh/Vertex.h index 2c92fe6c..e89c22f9 100644 --- a/private/ProgressiveMesh/Vertex.h +++ b/private/ProgressiveMesh/Vertex.h @@ -41,7 +41,7 @@ class Vertex const cd::DynamicArray& GetAdjacentFaces() const { return m_adjacentFaces; } void SetCollapseCost(float cost) { m_collapseCost = cost; } - float GetCollapseCost() const { return m_collapseCost; } + float GetCollapseCost() const; void SetCollapseTarget(cd::VertexID target) { m_collapseTarget = target; } cd::VertexID GetCollapseTarget() const { return m_collapseTarget; } diff --git a/public/Container/IterablePriorityQueueProxy.hpp b/public/Container/IterablePriorityQueueProxy.hpp new file mode 100644 index 00000000..f053e477 --- /dev/null +++ b/public/Container/IterablePriorityQueueProxy.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +namespace cd +{ + +// IterablePriorityQueueProxy is a helper to iterate elements in std::priority_queue which mostly is used to debug. +// In C++, the best priority queue I think is std::multiset which supports update operation. (Just erase and insert again!) +// Emmmm, std::priority is nothing but a wrapper of std::make_heap/push_heap/pop_heap. +template +concept use_vector_container = requires(T) +{ + {std::vector{}} -> std::same_as; +}; + +template requires use_vector_container +class IterablePriorityQueueProxy +{ +public: + IterablePriorityQueueProxy() = delete; + IterablePriorityQueueProxy(const T& pq) : m_pPriorityQueue(&pq) {} + IterablePriorityQueueProxy(const IterablePriorityQueueProxy&) = default; + IterablePriorityQueueProxy& operator=(const IterablePriorityQueueProxy&) = default; + IterablePriorityQueueProxy(IterablePriorityQueueProxy&&) = default; + IterablePriorityQueueProxy& operator=(IterablePriorityQueueProxy&&) = default; + ~IterablePriorityQueueProxy() = default; + + auto begin() const { return &m_pPriorityQueue->top(); }; + auto end() const { return begin() + m_pPriorityQueue->size(); }; + +private: + const T* m_pPriorityQueue = nullptr; +}; + +} \ No newline at end of file