[Bf-blender-cvs] [80f7f1070f1] master: Geometry Nodes: Add Attribute interpolation for polygon domains

Hans Goudey noreply at git.blender.org
Tue Mar 9 19:39:14 CET 2021


Commit: 80f7f1070f177ae543f2fa35dd5d458e87ff30c1
Author: Hans Goudey
Date:   Tue Mar 9 13:39:05 2021 -0500
Branches: master
https://developer.blender.org/rB80f7f1070f177ae543f2fa35dd5d458e87ff30c1

Geometry Nodes: Add Attribute interpolation for polygon domains

This commit adds interpolation to and from attribute on the polygon
domain. Interpolation is done automatically when a node uses attributes
on two different domains. The following are the new interpolations and
corresponding simple test cases:
- **Point to Polygon**: Painting the shade smooth attribute in weight
  paint mode
- **Polygon to Point**: Moving points along a normal based on the
  material index
- **Polygon to Corner**: Scaling a UV map with the material index
  before sampling a texture

{F9881516}

This is also necessary for an improved implementation of the `normal`
attribute.

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

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

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 31809b1ffec..53defc89b7e 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -256,6 +256,157 @@ static ReadAttributePtr adapt_mesh_domain_point_to_corner(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_corner_to_polygon_impl(const Mesh &mesh,
+                                                     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 T value = old_values[loop_index];
+      mixer.mix_in(poly_index, value);
+    }
+  }
+
+  mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_corner_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(dummy);
+    if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+      Array<T> values(mesh.totpoly);
+      adapt_mesh_domain_corner_to_polygon_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,
+                                             MutableSpan<T> r_values)
+{
+  BLI_assert(r_values.size() == mesh.totvert);
+  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];
+      const int point_index = loop.v;
+      mixer.mix_in(point_index, value);
+    }
+  }
+
+  mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_polygon_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_polygon_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;
+}
+
+template<typename T>
+void adapt_mesh_domain_polygon_to_corner_impl(const Mesh &mesh,
+                                              const Span<T> old_values,
+                                              MutableSpan<T> r_values)
+{
+  BLI_assert(r_values.size() == mesh.totloop);
+
+  for (const int poly_index : IndexRange(mesh.totpoly)) {
+    const MPoly &poly = mesh.mpoly[poly_index];
+    MutableSpan<T> poly_corner_values = r_values.slice(poly.loopstart, poly.totloop);
+    poly_corner_values.fill(old_values[poly_index]);
+  }
+}
+
+static ReadAttributePtr adapt_mesh_domain_polygon_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_polygon_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;
+}
+
+/**
+ * \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_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)) {
+      MLoop &loop = mesh.mloop[loop_index];
+      const int point_index = loop.v;
+      mixer.mix_in(poly_index, old_values[point_index]);
+    }
+  }
+  mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_point_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(dummy);
+    if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+      Array<T> values(mesh.totpoly);
+      adapt_mesh_domain_point_to_polygon_impl<T>(mesh, attribute->get_span<T>(), values);
+      new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+                                                                   std::move(values));
+    }
+  });
+  return new_attribute;
+}
+
 }  // namespace blender::bke
 
 ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attribute,
@@ -277,6 +428,8 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr
       switch (new_domain) {
         case ATTR_DOMAIN_POINT:
           return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute));
+        case ATTR_DOMAIN_POLYGON:
+          return blender::bke::adapt_mesh_domain_corner_to_polygon(*mesh_, std::move(attribute));
         default:
           break;
       }
@@ -286,9 +439,23 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr
       switch (new_domain) {
         case ATTR_DOMAIN_CORNER:
           return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute));
+        case ATTR_DOMAIN_POLYGON:
+          return blender::bke::adapt_mesh_domain_point_to_polygon(*mesh_, std::move(attribute));
+        default:
+          break;
+      }
+      break;
+    }
+    case ATTR_DOMAIN_POLYGON: {
+      switch (new_domain) {
+        case ATTR_DOMAIN_POINT:
+          return blender::bke::adapt_mesh_domain_polygon_to_point(*mesh_, std::move(attribute));
+        case ATTR_DOMAIN_CORNER:
+          return blender::bke::adapt_mesh_domain_polygon_to_corner(*mesh_, std::move(attribute));
         default:
           break;
       }
+      break;
     }
     default:
       break;



More information about the Bf-blender-cvs mailing list