[Bf-blender-cvs] [e064777cac0] master: OpenSubdiv: Correct topology cpmparator

Sergey Sharybin noreply at git.blender.org
Wed Jan 16 11:33:42 CET 2019


Commit: e064777cac02a065e20a9453f6d2a03651250d56
Author: Sergey Sharybin
Date:   Tue Jan 15 14:00:57 2019 +0100
Branches: master
https://developer.blender.org/rBe064777cac02a065e20a9453f6d2a03651250d56

OpenSubdiv: Correct topology cpmparator

This fixes following errors:

- The code didn't work correctly for edges reconstructed by
  the OpenSubdiv's topology refiner (due to indexing
  difference).

- Sharpness of non-manifold and boundary edges was not
  working correctly.

===================================================================

M	intern/opensubdiv/CMakeLists.txt
A	intern/opensubdiv/internal/opensubdiv_edge_map.h
M	intern/opensubdiv/internal/opensubdiv_topology_refiner.cc
M	intern/opensubdiv/internal/opensubdiv_util.h

===================================================================

diff --git a/intern/opensubdiv/CMakeLists.txt b/intern/opensubdiv/CMakeLists.txt
index e145500e019..e6ad305ffc7 100644
--- a/intern/opensubdiv/CMakeLists.txt
+++ b/intern/opensubdiv/CMakeLists.txt
@@ -75,6 +75,7 @@ if(WITH_OPENSUBDIV)
 		internal/opensubdiv_converter_orient_impl.h
 		internal/opensubdiv_device_context_cuda.h
 		internal/opensubdiv_device_context_opencl.h
+		internal/opensubdiv_edge_map.h
 		internal/opensubdiv_evaluator_internal.h
 		internal/opensubdiv_gl_mesh_draw.h
 		internal/opensubdiv_gl_mesh_fvar.h
diff --git a/intern/opensubdiv/internal/opensubdiv_edge_map.h b/intern/opensubdiv/internal/opensubdiv_edge_map.h
new file mode 100644
index 00000000000..8825f663c15
--- /dev/null
+++ b/intern/opensubdiv/internal/opensubdiv_edge_map.h
@@ -0,0 +1,159 @@
+// Copyright 2019 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifndef OPENSUBDIV_EDGE_MAP_H_
+#define OPENSUBDIV_EDGE_MAP_H_
+
+#include "internal/opensubdiv_util.h"
+
+namespace opensubdiv_capi {
+
+// Helper class to ease dealing with edge indexing.
+// Simply takes care of ensuring order of vertices is strictly defined.
+class EdgeKey {
+ public:
+  inline EdgeKey();
+  inline EdgeKey(int v1, int v2);
+
+  inline size_t hash() const;
+  inline bool operator==(const EdgeKey& other) const;
+
+  // These indices are guaranteed to be so v1 < v2.
+  int v1;
+  int v2;
+};
+
+// Map from an edge defined by its verticies index to a custom tag value.
+template<typename T>
+class EdgeTagMap {
+ public:
+  typedef EdgeKey key_type;
+  typedef T value_type;
+
+  inline EdgeTagMap();
+
+  // Modifiers.
+  inline void clear();
+  inline void insert(const key_type& key, const value_type& value);
+  inline void insert(int v1, int v2, const value_type& value);
+
+  // Lookup.
+  value_type& at(const key_type& key);
+  value_type& at(key_type&& key);
+  value_type& at(int v1, int v2);
+
+  value_type& operator[](const key_type& key);
+  value_type& operator[](key_type&& key);
+
+ protected:
+  unordered_map<key_type, value_type> edge_tags_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Implementation.
+
+// EdgeKey.
+
+EdgeKey::EdgeKey()
+    : v1(-1),
+      v2(-1) {
+}
+
+EdgeKey::EdgeKey(int v1, int v2) {
+  assert(v1 >= 0);
+  assert(v2 >= 0);
+  assert(v1 != v2);
+  if (v1 < v2) {
+    this->v1 = v1;
+    this->v2 = v2;
+  } else {
+    this->v1 = v2;
+    this->v2 = v1;
+  }
+}
+
+size_t EdgeKey::hash() const {
+  return (static_cast<uint64_t>(v1) << 32) | v2;
+}
+
+bool EdgeKey::operator==(const EdgeKey& other) const {
+  return v1 == other.v1 &&
+         v2 == other.v2;
+}
+
+// EdgeTagMap.
+
+template<typename T>
+EdgeTagMap<T>::EdgeTagMap() {
+}
+
+template<typename T>
+void EdgeTagMap<T>::clear() {
+  edge_tags_.clear();
+}
+
+template<typename T>
+void EdgeTagMap<T>::insert(const key_type& key, const value_type& value) {
+  edge_tags_.insert(make_pair(key, value));
+}
+
+template<typename T>
+void EdgeTagMap<T>::insert(int v1, int v2, const value_type& value) {
+  insert(EdgeKey(v1, v2), value);
+}
+
+template<typename T>
+typename EdgeTagMap<T>::value_type& EdgeTagMap<T>::at(const key_type& key) {
+  return edge_tags_.at[key];
+}
+
+template<typename T>
+typename EdgeTagMap<T>::value_type& EdgeTagMap<T>::at(key_type&& key) {
+  return edge_tags_.at[key];
+}
+
+template<typename T>
+typename EdgeTagMap<T>::value_type& EdgeTagMap<T>::at(int v1, int v2) {
+  return edge_tags_.at(EdgeKey(v1, v2));
+}
+
+template<typename T>
+typename EdgeTagMap<T>::value_type& EdgeTagMap<T>::operator[](
+    const key_type& key) {
+  return edge_tags_[key];
+}
+
+template<typename T>
+typename EdgeTagMap<T>::value_type& EdgeTagMap<T>::operator[](key_type&& key) {
+  return edge_tags_[key];
+}
+
+}  // namespace opensubdiv_capi
+
+namespace std {
+
+template <>
+struct hash<opensubdiv_capi::EdgeKey> {
+  std::size_t operator()(const opensubdiv_capi::EdgeKey& key) const {
+    return key.hash();
+  }
+};
+
+}  // namespace std
+
+#endif  // OPENSUBDIV_EDGE_MAP_H_
diff --git a/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc b/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc
index 296e373c31f..cbd076b256e 100644
--- a/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc
+++ b/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc
@@ -23,6 +23,7 @@
 #include "MEM_guardedalloc.h"
 #include "internal/opensubdiv_converter_factory.h"
 #include "internal/opensubdiv_converter_internal.h"
+#include "internal/opensubdiv_edge_map.h"
 #include "internal/opensubdiv_internal.h"
 #include "internal/opensubdiv_topology_refiner_internal.h"
 #include "internal/opensubdiv_util.h"
@@ -152,7 +153,7 @@ void fillFacePtexIndexOffset(const OpenSubdiv_TopologyRefiner* topology_refiner,
   }
 }
 
-//////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
 // Face-varying data.
 
 int getNumFVarChannels(
@@ -185,7 +186,7 @@ const int* getFaceFVarValueIndices(
   return &base_level->GetFaceFVarValues(face_index, channel)[0];
 }
 
-//////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
 // Internal helpers.
 
 void assignFunctionPointers(OpenSubdiv_TopologyRefiner* topology_refiner) {
@@ -249,6 +250,7 @@ void openSubdiv_deleteTopologyRefiner(
 ////////////////////////////////////////////////////////////////////////////////
 // Comparison with converter.
 
+namespace opensubdiv_capi {
 namespace {
 
 ///////////////////////////////////////////////////////////
@@ -279,7 +281,7 @@ bool checkOptionsMatches(
   return true;
 }
 
-bool checkGeometryCoountersMatches(
+bool checkGeometryCountersMatches(
     const OpenSubdiv::Far::TopologyRefiner* topology_refiner,
     const OpenSubdiv_Converter* converter) {
   using OpenSubdiv::Far::TopologyLevel;
@@ -295,32 +297,115 @@ bool checkPreliminaryMatches(
     const OpenSubdiv_Converter* converter) {
   return checkSchemeTypeMatches(topology_refiner, converter) &&
          checkOptionsMatches(topology_refiner, converter) &&
-         checkGeometryCoountersMatches(topology_refiner, converter);
+         checkGeometryCountersMatches(topology_refiner, converter);
 }
 
 ///////////////////////////////////////////////////////////
 // Geometry comparison.
 
-bool checkGeometryEdgesMatch(
-    const OpenSubdiv::Far::TopologyRefiner* topology_refiner,
-    const OpenSubdiv_Converter* converter) {
-  using OpenSubdiv::Far::ConstIndexArray;
-  using OpenSubdiv::Far::TopologyLevel;
-  const TopologyLevel& base_level = topology_refiner->GetLevel(0);
-  const int num_edges = base_level.GetNumEdges();
-  for (int edge_index = 0; edge_index < num_edges; ++edge_index) {
-    const ConstIndexArray& edge_vertices =
-        base_level.GetEdgeVertices(edge_index);
-    int conv_edge_vertices[2];
-    converter->getEdgeVertices(converter, edge_index, conv_edge_vertices);
-    if (conv_edge_vertices[0] != edge_vertices[0] ||
-        conv_edge_vertices[1] != edge_vertices[1]) {
+// A thin wrapper around index like array which does cyclic access. This means,
+// it basically does indices[requested_index % num_indices].
+//
+// NOTE: This array does not own the memory.
+//
+// TODO(sergey): Consider moving this to a more reusable place.
+class CyclicArray {
+ public:
+  typedef int value_type;
+  typedef int size_type;
+  static constexpr size_type npos = -1;
+
+  explicit CyclicArray(const std::vector<int>& data)
+      : data_(data.data()),
+        size_(data.size()) {
+  }
+
+  explicit CyclicArray(const OpenSubdiv::Far::ConstIndexArray& data)
+      : data_(&data[0]),
+        size_(data.size()) {
+  }
+
+  inline value_type operator[](int index) const {
+    assert(index >= 0);
+    // TODO(sergey): Check whether doing check for element index exceeding total
+    // number of indices prior to modulo helps performance.
+    return data_[index % size()];
+  }
+
+  inline size_type size() const {
+    return size_;
+  }
+
+  // Find index of first occurrence of a given value.
+  inline size_type find(const value_type value) const {
+    const int num_indices = size();
+    for (size_type i = 0; i < num_indices; ++i) {
+      if (value == (*this)[i]) {
+        return i;
+      }
+    }
+    return npos;
+  }
+
+ protected:
+  const value_type* data_;
+  const size_type size_;
+};
+
+bool compareCyclicForward(const CyclicArray& array_a,
+                          const int start_a,
+                          const CyclicArray& array_b,
+                          const int start_b) {
+  const int num_elements = array_a.size();
+  for (int i = 0; i < num_elements; ++i) {
+    if (array_a[start_a + i] != array_b[start_b + i]) {
       return false;
     }
   }
   return true;
 }
 
+bool compareCyclicBackward(const CyclicArray& array_a,
+                           const int start_a,
+                           const CyclicArray& array_b,
+                           const int start_b) {
+  const int num_elements = array_a.size();
+  // TODO(sergey): Some optimization might be possible with memcmp trickery.
+  for (int i = 0; i < num_elements; ++i) {
+    if (array_a[start_a + (num_elements - i - 1)] !=
+        array_b[start_b + (num_elements - i - 1)]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Utility function dedicated for checking whether whether verticies indices
+//

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list