diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2020-05-19 13:38:52 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2020-05-27 13:07:16 +0300 |
commit | ece54172d001332ca9ea0f2046276b7d03547190 (patch) | |
tree | c38e9352b6f2828231caef60d3f15bfacccbdf78 | |
parent | 16aef5dc4ae7d8dc0347fc6cd3787c17b71ed169 (diff) |
OpenSubdiv: Use explicit storage for edge sharpness
Similar to previous change in vertex sharpness, explicitly store value
provided by the converter.
Allows to avoid rather fragile check for boundary edges.
Also allows to avoid need in constructing edge map. This lowers memory
footprint of the comparison process and avoids memory allocations
during the comparison (which is an extra benefit from the performance
point of view).
4 files changed, 147 insertions, 90 deletions
diff --git a/intern/opensubdiv/internal/topology/mesh_topology.cc b/intern/opensubdiv/internal/topology/mesh_topology.cc index f8832d61cd0..e4469a83f75 100644 --- a/intern/opensubdiv/internal/topology/mesh_topology.cc +++ b/intern/opensubdiv/internal/topology/mesh_topology.cc @@ -23,7 +23,7 @@ namespace blender { namespace opensubdiv { -MeshTopology::MeshTopology() +MeshTopology::MeshTopology() : num_vertices_(0), num_edges_(0) { } @@ -31,21 +31,102 @@ MeshTopology::~MeshTopology() { } +//////////////////////////////////////////////////////////////////////////////// +// Vertices. + void MeshTopology::setNumVertices(int num_vertices) { - vertices.resize(num_vertices); + num_vertices_ = num_vertices; } + int MeshTopology::getNumVertices() const { - return vertices.size(); + return num_vertices_; } void MeshTopology::setVertexSharpness(int vertex_index, float sharpness) { assert(vertex_index >= 0); - assert(vertex_index < vertices.size()); + assert(vertex_index < getNumVertices()); + + ensureVertexTagsSize(vertex_index + 1); + + vertex_tags_[vertex_index].sharpness = sharpness; +} + +float MeshTopology::getVertexSharpness(int vertex_index) const +{ + assert(vertex_index >= 0); + assert(vertex_index < getNumVertices()); - vertices[vertex_index].sharpness = sharpness; + if (vertex_index >= vertex_tags_.size()) { + // Sharpness for the vertex was never provided. + return 0.0f; + } + + return vertex_tags_[vertex_index].sharpness; +} + +void MeshTopology::ensureVertexTagsSize(int num_vertices) +{ + if (vertex_tags_.size() < num_vertices) { + vertex_tags_.resize(num_vertices); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Edges. + +void MeshTopology::setNumEdges(int num_edges) +{ + num_edges_ = num_edges; +} + +int MeshTopology::getNumEdges() const +{ + return num_edges_; +} + +void MeshTopology::setEdgeSharpness(int edge_index, float sharpness) +{ + assert(edge_index >= 0); + + ensureNumEdgesAtLeast(edge_index + 1); + + if (sharpness < 1e-6f) { + return; + } + + ensureEdgeTagsSize(edge_index + 1); + + edge_tags_[edge_index].sharpness = sharpness; +} + +float MeshTopology::getEdgeSharpness(int edge_index) const +{ + assert(edge_index >= 0); + + if (edge_index >= edge_tags_.size()) { + // NOTE: It's possible that full topology is not known and that there was + // never sharpness assigned to any of the edges. + return 0.0f; + } + + return edge_tags_[edge_index].sharpness; +} + +void MeshTopology::ensureNumEdgesAtLeast(int num_edges) +{ + if (getNumEdges() < num_edges) { + setNumEdges(num_edges); + } +} + +void MeshTopology::ensureEdgeTagsSize(int num_edges) +{ + if (edge_tags_.size() < num_edges) { + edge_tags_.resize(num_edges); + } } } // namespace opensubdiv diff --git a/intern/opensubdiv/internal/topology/mesh_topology.h b/intern/opensubdiv/internal/topology/mesh_topology.h index 9893c70dac8..183f5eb45d4 100644 --- a/intern/opensubdiv/internal/topology/mesh_topology.h +++ b/intern/opensubdiv/internal/topology/mesh_topology.h @@ -27,7 +27,12 @@ struct OpenSubdiv_Converter; namespace blender { namespace opensubdiv { -class VertexTopology { +class VertexTopologyTag { + public: + float sharpness = 0.0f; +}; + +class EdgeTopologyTag { public: float sharpness = 0.0f; }; @@ -45,12 +50,44 @@ class MeshTopology { MeshTopology &operator=(const MeshTopology &other) = default; MeshTopology &operator=(MeshTopology &&other) = default; + ////////////////////////////////////////////////////////////////////////////// + // Vertices. + void setNumVertices(int num_vertices); int getNumVertices() const; void setVertexSharpness(int vertex_index, float sharpness); + float getVertexSharpness(int vertex_index) const; + + ////////////////////////////////////////////////////////////////////////////// + // Edges. + + void setNumEdges(int num_edges); + + // NOTE: Unless full topology was specified will return number of edges based + // on last edge index for which topology tag was specified. + int getNumEdges() const; + + void setEdgeSharpness(int edge_index, float sharpness); + float getEdgeSharpness(int edge_index) const; + + protected: + // Unless full topology was specified the number of edges is not know ahead + // of a time. + void ensureNumEdgesAtLeast(int num_edges); + + // Geometry tags are stored sparsly. + // + // These functions ensures that the storage can be addressed by an index which + // corresponds to the given size. + void ensureVertexTagsSize(int num_vertices); + void ensureEdgeTagsSize(int num_edges); + + int num_vertices_; + vector<VertexTopologyTag> vertex_tags_; - vector<VertexTopology> vertices; + int num_edges_; + vector<EdgeTopologyTag> edge_tags_; MEM_CXX_CLASS_ALLOC_FUNCS("MeshTopology"); }; diff --git a/intern/opensubdiv/internal/topology/topology_refiner_factory.cc b/intern/opensubdiv/internal/topology/topology_refiner_factory.cc index c9c72f18349..a0e0269936c 100644 --- a/intern/opensubdiv/internal/topology/topology_refiner_factory.cc +++ b/intern/opensubdiv/internal/topology/topology_refiner_factory.cc @@ -77,6 +77,7 @@ inline bool TopologyRefinerFactory<TopologyRefinerData>::resizeComponentTopology // Edges and edge-faces. const int num_edges = converter->getNumEdges(converter); + base_mesh_topology->setNumEdges(num_edges); setNumBaseEdges(refiner, num_edges); for (int edge_index = 0; edge_index < num_edges; ++edge_index) { const int num_edge_faces = converter->getNumEdgeFaces(converter, edge_index); @@ -161,9 +162,12 @@ inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTags( const int num_edges = converter->getNumEdges(converter); for (int edge_index = 0; edge_index < num_edges; ++edge_index) { const float sharpness = converter->getEdgeSharpness(converter, edge_index); + base_mesh_topology->setEdgeSharpness(edge_index, sharpness); + if (sharpness < 1e-6f) { continue; } + if (full_topology_specified) { setBaseEdgeSharpness(refiner, edge_index, sharpness); } diff --git a/intern/opensubdiv/internal/topology/topology_refiner_impl_compare.cc b/intern/opensubdiv/internal/topology/topology_refiner_impl_compare.cc index d51d0eb7f54..06612a9e6a1 100644 --- a/intern/opensubdiv/internal/topology/topology_refiner_impl_compare.cc +++ b/intern/opensubdiv/internal/topology/topology_refiner_impl_compare.cc @@ -18,7 +18,6 @@ #include "internal/topology/topology_refiner_impl.h" -#include "internal/base/edge_map.h" #include "internal/base/type.h" #include "internal/base/type_convert.h" #include "internal/topology/mesh_topology.h" @@ -233,102 +232,37 @@ bool checkGeometryMatches(const TopologyRefinerImpl *topology_refiner_impl, } //////////////////////////////////////////////////////////////////////////////// -// Compare attributes which affects on topology +// Compare attributes which affects on topology. -inline bool checkSingleEdgeSharpnessMatch(const OpenSubdiv::Far::TopologyLevel &base_level, - int base_level_edge_index, - const OpenSubdiv_Converter *converter, - int converter_edge_index) +// TODO(sergey): Make this function usable by factory as well. +float getEffectiveEdgeSharpness(const OpenSubdiv_Converter *converter, const int edge_index) { - // NOTE: Boundary and non-manifold edges are internally forced to an infinite - // sharpness. So we can not reliably compare those. - // - // TODO(sergey): Watch for NON_MANIFOLD_SHARP option. - if (base_level.IsEdgeBoundary(base_level_edge_index) || - base_level.IsEdgeNonManifold(base_level_edge_index)) { - return true; - } - const float sharpness = base_level.GetEdgeSharpness(base_level_edge_index); - const float converter_sharpness = converter->getEdgeSharpness(converter, converter_edge_index); - if (sharpness != converter_sharpness) { - return false; + if (converter->getEdgeSharpness != nullptr) { + return converter->getEdgeSharpness(converter, edge_index); } - return true; -} -inline bool checkSingleEdgeTagMatch(const OpenSubdiv::Far::TopologyLevel &base_level, - int base_level_edge_index, - const OpenSubdiv_Converter *converter, - int converter_edge_index) -{ - return checkSingleEdgeSharpnessMatch( - base_level, base_level_edge_index, converter, converter_edge_index); + return 0.0f; } -// Compares edge tags between topology refiner and converter in a case when -// converter specifies a full topology. -// This is simplest loop, since we know that order of edges matches. -bool checkEdgeTagsMatchFullTopology(const TopologyRefinerImpl *topology_refiner_impl, - const OpenSubdiv_Converter *converter) +bool checkEdgeTagsMatch(const TopologyRefinerImpl *topology_refiner_impl, + const OpenSubdiv_Converter *converter) { - using OpenSubdiv::Far::ConstIndexArray; - using OpenSubdiv::Far::TopologyLevel; - const TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner_impl); - const int num_edges = base_level.GetNumEdges(); - for (int edge_index = 0; edge_index < num_edges; ++edge_index) { - if (!checkSingleEdgeTagMatch(base_level, edge_index, converter, edge_index)) { - return false; - } - } - return true; -} + const MeshTopology &base_mesh_topology = topology_refiner_impl->base_mesh_topology; -// Compares tags of edges in the case when orientation of edges is left up to -// OpenSubdiv. In this case we do need to take care of mapping edges from the -// converter to current topology refiner, since the order is not guaranteed. -bool checkEdgeTagsMatchAutoOrient(const TopologyRefinerImpl *topology_refiner_impl, - const OpenSubdiv_Converter *converter) -{ - using OpenSubdiv::Far::ConstIndexArray; - using OpenSubdiv::Far::TopologyLevel; - const TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner_impl); - const int num_edges = base_level.GetNumEdges(); - // Create mapping for quick lookup of edge index from its vertices indices. - // - // TODO(sergey): Consider caching it in some sort of wrapper around topology - // refiner. - EdgeTagMap<int> edge_map; + const int num_edges = base_mesh_topology.getNumEdges(); for (int edge_index = 0; edge_index < num_edges; ++edge_index) { - ConstIndexArray edge_vertices = base_level.GetEdgeVertices(edge_index); - edge_map.insert(edge_vertices[0], edge_vertices[1], edge_index); - } - // Compare all edges. - for (int converter_edge_index = 0; converter_edge_index < num_edges; ++converter_edge_index) { - // Get edge vertices indices, and lookup corresponding edge index in the - // base topology level. - int edge_vertices[2]; - converter->getEdgeVertices(converter, converter_edge_index, edge_vertices); - const int base_level_edge_index = edge_map.at(edge_vertices[0], edge_vertices[1]); - // Perform actual test. - if (!checkSingleEdgeTagMatch( - base_level, base_level_edge_index, converter, converter_edge_index)) { + const float current_sharpness = base_mesh_topology.getEdgeSharpness(edge_index); + const float requested_sharpness = getEffectiveEdgeSharpness(converter, edge_index); + + if (current_sharpness != requested_sharpness) { return false; } } - return true; -} -bool checkEdgeTagsMatch(const TopologyRefinerImpl *topology_refiner_impl, - const OpenSubdiv_Converter *converter) -{ - if (converter->specifiesFullTopology(converter)) { - return checkEdgeTagsMatchFullTopology(topology_refiner_impl, converter); - } - else { - return checkEdgeTagsMatchAutoOrient(topology_refiner_impl, converter); - } + return true; } +// TODO(sergey): Make this function usable by factory as well. float getEffectiveVertexSharpness(const OpenSubdiv_Converter *converter, const int vertex_index) { if (converter->isInfiniteSharpVertex != nullptr && @@ -350,13 +284,14 @@ bool checkVertexSharpnessMatch(const TopologyRefinerImpl *topology_refiner_impl, const int num_vertices = base_mesh_topology.getNumVertices(); for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) { - const float current_sharpness = base_mesh_topology.vertices[vertex_index].sharpness; + const float current_sharpness = base_mesh_topology.getVertexSharpness(vertex_index); const float requested_sharpness = getEffectiveVertexSharpness(converter, vertex_index); if (current_sharpness != requested_sharpness) { return false; } } + return true; } |