[Bf-blender-cvs] [ae1649e9057] temp-geometry-nodes-extrude-mesh: Mix boolean attributes with a new "or" mixer

Hans Goudey noreply at git.blender.org
Sat Jan 22 00:57:37 CET 2022


Commit: ae1649e905701420afe7cf1566fdafa438b3472a
Author: Hans Goudey
Date:   Fri Jan 21 17:57:27 2022 -0600
Branches: temp-geometry-nodes-extrude-mesh
https://developer.blender.org/rBae1649e905701420afe7cf1566fdafa438b3472a

Mix boolean attributes with a new "or" mixer

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

M	source/blender/blenkernel/BKE_attribute_math.hh
M	source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc

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

diff --git a/source/blender/blenkernel/BKE_attribute_math.hh b/source/blender/blenkernel/BKE_attribute_math.hh
index a7bdca06790..36a08b18963 100644
--- a/source/blender/blenkernel/BKE_attribute_math.hh
+++ b/source/blender/blenkernel/BKE_attribute_math.hh
@@ -230,6 +230,43 @@ template<typename T> class SimpleMixer {
   }
 };
 
+/**
+ * Mixes together booleans with "or" while fitting the same interface as the other mixers in order
+ * to make using it simpler. This mixing method has a few benefits:
+ *  - An "average" for selections is relatively meaningless.
+ *  - Predictable selection propagation is very super important.
+ *  - It's generally  easier to remove an element from a selection that is slightly too large than
+ *    the opposite.
+ */
+class BooleanPropagationMixer {
+ private:
+  MutableSpan<bool> buffer_;
+
+ public:
+  /**
+   * \param buffer: Span where the interpolated values should be stored.
+   */
+  BooleanPropagationMixer(MutableSpan<bool> buffer) : buffer_(buffer)
+  {
+    buffer_.fill(false);
+  }
+
+  /**
+   * Mix a #value into the element with the given #index.
+   */
+  void mix_in(const int64_t index, const bool value, [[maybe_unused]] const float weight = 1.0f)
+  {
+    buffer_[index] |= value;
+  }
+
+  /**
+   * Does not do anything, since the mixing is trivial.
+   */
+  void finalize()
+  {
+  }
+};
+
 /**
  * This mixer accumulates values in a type that is different from the one that is mixed.
  * Some types cannot encode the floating point weights in their values (e.g. int and bool).
@@ -291,7 +328,7 @@ class ColorGeometryMixer {
 };
 
 template<typename T> struct DefaultMixerStruct {
-  /* Use void by default. This can be check for in `if constexpr` statements. */
+  /* Use void by default. This can be checked for in `if constexpr` statements. */
   using type = void;
 };
 template<> struct DefaultMixerStruct<float> {
@@ -327,6 +364,20 @@ template<> struct DefaultMixerStruct<bool> {
   using type = SimpleMixerWithAccumulationType<bool, float, float_to_bool>;
 };
 
+template<typename T> struct DefaultPropatationMixerStruct {
+  /* Use void by default. This can be checked for in `if constexpr` statements. */
+  using type = typename DefaultMixerStruct<T>::type;
+};
+
+template<> struct DefaultPropatationMixerStruct<bool> {
+  using type = BooleanPropagationMixer;
+};
+
+/* This mixer is meant for propagating attributes when creating new geometry. A key difference
+ * with the default mixer is that booleans are mixed with "or" instead of "at least half". */
+template<typename T>
+using DefaultPropatationMixer = typename DefaultPropatationMixerStruct<T>::type;
+
 /* Utility to get a good default mixer for a given type. This is `void` when there is no default
  * mixer for the given type. */
 template<typename T> using DefaultMixer = typename DefaultMixerStruct<T>::type;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
index 7ff688377a8..8d311906527 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
@@ -216,7 +216,7 @@ template<typename T, typename GetMixIndicesFn>
 void copy_with_mixing(MutableSpan<T> dst, Span<T> src, GetMixIndicesFn get_mix_indices_fn)
 {
   threading::parallel_for(dst.index_range(), 512, [&](const IndexRange range) {
-    attribute_math::DefaultMixer<T> mixer{dst.slice(range)};
+    attribute_math::DefaultPropatationMixer<T> mixer{dst.slice(range)};
     for (const int i_dst : IndexRange(range.size())) {
       for (const int i_src : get_mix_indices_fn(range[i_dst])) {
         mixer.mix_in(i_dst, src[i_src]);
@@ -424,7 +424,7 @@ static void extrude_mesh_edges(MeshComponent &component,
   Array<float3> vert_offsets;
   if (!edge_offsets.is_single()) {
     vert_offsets.reinitialize(orig_vert_size);
-    attribute_math::DefaultMixer<float3> mixer(vert_offsets);
+    attribute_math::DefaultPropatationMixer<float3> mixer(vert_offsets);
     for (const int i_edge : edge_selection) {
       const MEdge &edge = orig_edges[i_edge];
       const float3 offset = edge_offsets[i_edge];
@@ -568,7 +568,7 @@ static void extrude_mesh_edges(MeshComponent &component,
               /* Both corners on each vertical edge of the side polygon get the same value,
                * so there are only two unique values to mix. */
               Array<T> side_poly_corner_data(2);
-              attribute_math::DefaultMixer<T> mixer{side_poly_corner_data};
+              attribute_math::DefaultPropatationMixer<T> mixer{side_poly_corner_data};
 
               const MEdge &duplicate_edge = duplicate_edges[i_edge_selection];
               const int new_vert_1 = duplicate_edge.v1;
@@ -684,7 +684,7 @@ static void extrude_mesh_face_regions(MeshComponent &component,
   Array<float3> vert_offsets;
   if (!poly_offsets.is_single()) {
     vert_offsets.reinitialize(orig_vert_size);
-    attribute_math::DefaultMixer<float3> mixer(vert_offsets);
+    attribute_math::DefaultPropatationMixer<float3> mixer(vert_offsets);
     for (const int i_poly : poly_selection) {
       const MPoly &poly = orig_polys[i_poly];
       const float3 offset = poly_offsets[i_poly];
@@ -1177,8 +1177,14 @@ static void extrude_individual_mesh_faces(MeshComponent &component,
                 const int i_loop_prev = (i == 0) ? poly.totloop - 1 : i - 1;
                 const int orig_index = poly_loops[i].e;
                 const int orig_index_prev = poly_loops[i_loop_prev].e;
-                connect_data[poly_corner_range[i]] = attribute_math::mix2(
-                    0.5f, data[orig_index], data[orig_index_prev]);
+                if constexpr (std::is_same_v<T, bool>) {
+                  /* Propagate selections with "or" instead of "at least half". */
+                  connect_data[poly_corner_range[i]] = data[orig_index] || data[orig_index_prev];
+                }
+                else {
+                  connect_data[poly_corner_range[i]] = attribute_math::mix2(
+                      0.5f, data[orig_index], data[orig_index_prev]);
+                }
               }
             }
           });



More information about the Bf-blender-cvs mailing list