[Bf-blender-cvs] [97b83b6a678] master: Geometry Nodes: Implicit interpolations to and from the edge domain

Hans Goudey noreply at git.blender.org
Fri Mar 19 14:00:01 CET 2021


Commit: 97b83b6a6781b613268d8d65244b96583bf2a981
Author: Hans Goudey
Date:   Fri Mar 19 08:59:56 2021 -0400
Branches: master
https://developer.blender.org/rB97b83b6a6781b613268d8d65244b96583bf2a981

Geometry Nodes: Implicit interpolations to and from the edge domain

This patch adds the remaining 6 interpolations for mesh domains.
The new interpolations are:
 - Corner / point / polygon to edge
 - Edge to corner / point / polygon

After this it is possible to adapt an attribute to and from every
mesh domain. This is simple to test with the "Attribute Convert" node.

Though, as a note for the future, there are still some improvements
possible to the interpolations, like lazily calculating values for the
interpolations where it's possible, and slightly improving the
algorithms used for some interpolations, like using corner angles
for polygon to point.

Differential Revision: https://developer.blender.org/D10765

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

M	source/blender/blenkernel/intern/geometry_component_mesh.cc

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

diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
index 8ee2142799d..eee7c2ff09e 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -296,6 +296,47 @@ static ReadAttributePtr adapt_mesh_domain_corner_to_polygon(const Mesh &mesh,
   return new_attribute;
 }
 
+template<typename T>
+static void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh,
+                                                  Span<T> old_values,
+                                                  MutableSpan<T> r_values)
+{
+  BLI_assert(r_values.size() == mesh.totedge);
+  attribute_math::DefaultMixer<T> mixer(r_values);
+
+  for (const int poly_index : IndexRange(mesh.totpoly)) {
+    const MPoly &poly = mesh.mpoly[poly_index];
+
+    /* For every edge, mix values from the two adjacent corners (the current and next corner). */
+    for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+      const int loop_index_next = (loop_index + 1) % poly.totloop;
+      const MLoop &loop = mesh.mloop[loop_index];
+      const int edge_index = loop.e;
+      mixer.mix_in(edge_index, old_values[loop_index]);
+      mixer.mix_in(edge_index, old_values[loop_index_next]);
+    }
+  }
+
+  mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_corner_to_edge(const Mesh &mesh,
+                                                         ReadAttributePtr attribute)
+{
+  ReadAttributePtr new_attribute;
+  const CustomDataType data_type = attribute->custom_data_type();
+  attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+    using T = decltype(dummy);
+    if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+      Array<T> values(mesh.totedge);
+      adapt_mesh_domain_corner_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
+      new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+                                                                   std::move(values));
+    }
+  });
+  return new_attribute;
+}
+
 template<typename T>
 void adapt_mesh_domain_polygon_to_point_impl(const Mesh &mesh,
                                              Span<T> old_values,
@@ -365,6 +406,42 @@ static ReadAttributePtr adapt_mesh_domain_polygon_to_corner(const Mesh &mesh,
   return new_attribute;
 }
 
+template<typename T>
+void adapt_mesh_domain_polygon_to_edge_impl(const Mesh &mesh,
+                                            const Span<T> old_values,
+                                            MutableSpan<T> r_values)
+{
+  BLI_assert(r_values.size() == mesh.totedge);
+  attribute_math::DefaultMixer<T> mixer(r_values);
+
+  for (const int poly_index : IndexRange(mesh.totpoly)) {
+    const MPoly &poly = mesh.mpoly[poly_index];
+    const T value = old_values[poly_index];
+    for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+      const MLoop &loop = mesh.mloop[loop_index];
+      mixer.mix_in(loop.e, value);
+    }
+  }
+  mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_polygon_to_edge(const Mesh &mesh,
+                                                          ReadAttributePtr attribute)
+{
+  ReadAttributePtr new_attribute;
+  const CustomDataType data_type = attribute->custom_data_type();
+  attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+    using T = decltype(dummy);
+    if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+      Array<T> values(mesh.totedge);
+      adapt_mesh_domain_polygon_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
+      new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+                                                                   std::move(values));
+    }
+  });
+  return new_attribute;
+}
+
 /**
  * \note Theoretically this interpolation does not need to compute all values at once.
  * However, doing that makes the implementation simpler, and this can be optimized in the future if
@@ -406,6 +483,162 @@ static ReadAttributePtr adapt_mesh_domain_point_to_polygon(const Mesh &mesh,
   return new_attribute;
 }
 
+/**
+ * \note Theoretically this interpolation does not need to compute all values at once.
+ * However, doing that makes the implementation simpler, and this can be optimized in the future if
+ * only some values are required.
+ */
+template<typename T>
+static void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh,
+                                                 const Span<T> old_values,
+                                                 MutableSpan<T> r_values)
+{
+  BLI_assert(r_values.size() == mesh.totedge);
+  attribute_math::DefaultMixer<T> mixer(r_values);
+
+  for (const int edge_index : IndexRange(mesh.totedge)) {
+    const MEdge &edge = mesh.medge[edge_index];
+    mixer.mix_in(edge_index, old_values[edge.v1]);
+    mixer.mix_in(edge_index, old_values[edge.v2]);
+  }
+
+  mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_point_to_edge(const Mesh &mesh,
+                                                        ReadAttributePtr attribute)
+{
+  ReadAttributePtr new_attribute;
+  const CustomDataType data_type = attribute->custom_data_type();
+  attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+    using T = decltype(dummy);
+    if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+      Array<T> values(mesh.totedge);
+      adapt_mesh_domain_point_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
+      new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+                                                                   std::move(values));
+    }
+  });
+  return new_attribute;
+}
+
+template<typename T>
+void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh,
+                                           const Span<T> old_values,
+                                           MutableSpan<T> r_values)
+{
+  BLI_assert(r_values.size() == mesh.totloop);
+  attribute_math::DefaultMixer<T> mixer(r_values);
+
+  for (const int poly_index : IndexRange(mesh.totpoly)) {
+    const MPoly &poly = mesh.mpoly[poly_index];
+
+    /* For every corner, mix the values from the adjacent edges on the polygon. */
+    for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+      const int loop_index_prev = (loop_index - 1) % poly.totloop;
+      const MLoop &loop = mesh.mloop[loop_index];
+      const MLoop &loop_prev = mesh.mloop[loop_index_prev];
+      mixer.mix_in(loop_index, old_values[loop.e]);
+      mixer.mix_in(loop_index, old_values[loop_prev.e]);
+    }
+  }
+
+  mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_edge_to_corner(const Mesh &mesh,
+                                                         ReadAttributePtr attribute)
+{
+  ReadAttributePtr new_attribute;
+  const CustomDataType data_type = attribute->custom_data_type();
+  attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+    using T = decltype(dummy);
+    if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+      Array<T> values(mesh.totloop);
+      adapt_mesh_domain_edge_to_corner_impl<T>(mesh, attribute->get_span<T>(), values);
+      new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+                                                                   std::move(values));
+    }
+  });
+  return new_attribute;
+}
+
+template<typename T>
+static void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh,
+                                                 const Span<T> old_values,
+                                                 MutableSpan<T> r_values)
+{
+  BLI_assert(r_values.size() == mesh.totvert);
+  attribute_math::DefaultMixer<T> mixer(r_values);
+
+  for (const int edge_index : IndexRange(mesh.totedge)) {
+    const MEdge &edge = mesh.medge[edge_index];
+    const T value = old_values[edge_index];
+    mixer.mix_in(edge.v1, value);
+    mixer.mix_in(edge.v2, value);
+  }
+
+  mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_edge_to_point(const Mesh &mesh,
+                                                        ReadAttributePtr attribute)
+{
+  ReadAttributePtr new_attribute;
+  const CustomDataType data_type = attribute->custom_data_type();
+  attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+    using T = decltype(dummy);
+    if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+      Array<T> values(mesh.totvert);
+      adapt_mesh_domain_edge_to_point_impl<T>(mesh, attribute->get_span<T>(), values);
+      new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+                                                                   std::move(values));
+    }
+  });
+  return new_attribute;
+}
+
+/**
+ * \note Theoretically this interpolation does not need to compute all values at once.
+ * However, doing that makes the implementation simpler, and this can be optimized in the future if
+ * only some values are required.
+ */
+template<typename T>
+static void adapt_mesh_domain_edge_to_polygon_impl(const Mesh &mesh,
+                                                   const Span<T> old_values,
+                                                   MutableSpan<T> r_values)
+{
+  BLI_assert(r_values.size() == mesh.totpoly);
+  attribute_math::DefaultMixer<T> mixer(r_values);
+
+  for (const int poly_index : IndexRange(mesh.totpoly)) {
+    const MPoly &poly = mesh.mpoly[poly_index];
+    for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+      const MLoop &loop = mesh.mloop[loop_index];
+      mixer.mix_in(poly_index, old_values[loop.e]);
+    }
+  }
+
+  mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_edge_to_polygon(const Mesh &mesh,
+                                                          ReadAttributePtr attribute)
+{
+  ReadAttributePtr new_attribute;
+  const CustomDataType data_type = attribute->custom_data_type();
+  attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+    using T = decltype(dum

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list