[Bf-blender-cvs] [8e2c9f2dd31] master: Geometry Nodes: simplify using selection when evaluating fields

Jacques Lucke noreply at git.blender.org
Tue Dec 14 15:40:39 CET 2021


Commit: 8e2c9f2dd3118bfdb69ccf0ab2b9f968a854aae4
Author: Jacques Lucke
Date:   Tue Dec 14 15:40:16 2021 +0100
Branches: master
https://developer.blender.org/rB8e2c9f2dd3118bfdb69ccf0ab2b9f968a854aae4

Geometry Nodes: simplify using selection when evaluating fields

We often had to use two `FieldEvaluator` instances to first evaluate
the selection and then the remaining fields. Now both can be done
with a single `FieldEvaluator`. This results in less boilerplate code in
many cases.

Performance is not affected by this change. In a separate patch we
could improve performance by reusing evaluated sub-fields that are
used by the selection and the other fields.

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

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

M	source/blender/functions/FN_field.hh
M	source/blender/functions/intern/field.cc
M	source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
M	source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
M	source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
M	source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
M	source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
M	source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
M	source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
M	source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
M	source/blender/nodes/geometry/nodes/node_geo_set_id.cc
M	source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
M	source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
M	source/blender/nodes/geometry/nodes/node_geo_set_position.cc
M	source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
M	source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
M	source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
M	source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc

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

diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh
index cf96eff62bd..a591aaed34a 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -313,6 +313,9 @@ class FieldEvaluator : NonMovable, NonCopyable {
   Vector<OutputPointerInfo> output_pointer_infos_;
   bool is_evaluated_ = false;
 
+  Field<bool> selection_field_;
+  IndexMask selection_mask_;
+
  public:
   /** Takes #mask by pointer because the mask has to live longer than the evaluator. */
   FieldEvaluator(const FieldContext &context, const IndexMask *mask)
@@ -332,6 +335,18 @@ class FieldEvaluator : NonMovable, NonCopyable {
     BLI_assert(is_evaluated_);
   }
 
+  /**
+   * The selection field is evaluated first to determine which indices of the other fields should
+   * be evaluated. Calling this method multiple times will just replace the previously set
+   * selection field. Only the elements selected by both this selection and the selection provided
+   * in the constructor are calculated. If no selection field is set, it is assumed that all
+   * indices passed to the constructor are selected.
+   */
+  void set_selection(Field<bool> selection)
+  {
+    selection_field_ = std::move(selection);
+  }
+
   /**
    * \param field: Field to add to the evaluator.
    * \param dst: Mutable virtual array that the evaluated result for this field is be written into.
@@ -403,6 +418,8 @@ class FieldEvaluator : NonMovable, NonCopyable {
     return this->get_evaluated(field_index).typed<T>();
   }
 
+  IndexMask get_evaluated_selection_as_mask();
+
   /**
    * Retrieve the output of an evaluated boolean field and convert it to a mask, which can be used
    * to avoid calculations for unnecessary elements later on. The evaluator will own the indices in
diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc
index 5fa493c8336..604e5c6d13f 100644
--- a/source/blender/functions/intern/field.cc
+++ b/source/blender/functions/intern/field.cc
@@ -624,7 +624,7 @@ FieldInput::FieldInput(const CPPType &type, std::string debug_name)
  * FieldEvaluator.
  */
 
-static Vector<int64_t> indices_from_selection(const VArray<bool> &selection)
+static Vector<int64_t> indices_from_selection(IndexMask mask, const VArray<bool> &selection)
 {
   /* If the selection is just a single value, it's best to avoid calling this
    * function when constructing an IndexMask and use an IndexRange instead. */
@@ -633,14 +633,14 @@ static Vector<int64_t> indices_from_selection(const VArray<bool> &selection)
   Vector<int64_t> indices;
   if (selection.is_span()) {
     Span<bool> span = selection.get_internal_span();
-    for (const int64_t i : span.index_range()) {
+    for (const int64_t i : mask) {
       if (span[i]) {
         indices.append(i);
       }
     }
   }
   else {
-    for (const int i : selection.index_range()) {
+    for (const int i : mask) {
       if (selection[i]) {
         indices.append(i);
       }
@@ -681,14 +681,36 @@ int FieldEvaluator::add(GField field)
   return field_index;
 }
 
+static IndexMask evaluate_selection(const Field<bool> &selection_field,
+                                    const FieldContext &context,
+                                    IndexMask full_mask,
+                                    ResourceScope &scope)
+{
+  if (selection_field) {
+    VArray<bool> selection =
+        evaluate_fields(scope, {selection_field}, full_mask, context)[0].typed<bool>();
+    if (selection.is_single()) {
+      if (selection.get_internal_single()) {
+        return full_mask;
+      }
+      return IndexRange(0);
+    }
+    return scope.add_value(indices_from_selection(full_mask, selection)).as_span();
+  }
+  return full_mask;
+}
+
 void FieldEvaluator::evaluate()
 {
   BLI_assert_msg(!is_evaluated_, "Cannot evaluate fields twice.");
+
+  selection_mask_ = evaluate_selection(selection_field_, context_, mask_, scope_);
+
   Array<GFieldRef> fields(fields_to_evaluate_.size());
   for (const int i : fields_to_evaluate_.index_range()) {
     fields[i] = fields_to_evaluate_[i];
   }
-  evaluated_varrays_ = evaluate_fields(scope_, fields, mask_, context_, dst_varrays_);
+  evaluated_varrays_ = evaluate_fields(scope_, fields, selection_mask_, context_, dst_varrays_);
   BLI_assert(fields_to_evaluate_.size() == evaluated_varrays_.size());
   for (const int i : fields_to_evaluate_.index_range()) {
     OutputPointerInfo &info = output_pointer_infos_[i];
@@ -710,7 +732,13 @@ IndexMask FieldEvaluator::get_evaluated_as_mask(const int field_index)
     return IndexRange(0);
   }
 
-  return scope_.add_value(indices_from_selection(varray)).as_span();
+  return scope_.add_value(indices_from_selection(mask_, varray)).as_span();
+}
+
+IndexMask FieldEvaluator::get_evaluated_selection_as_mask()
+{
+  BLI_assert(is_evaluated_);
+  return selection_mask_;
 }
 
 }  // namespace blender::fn
diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
index adb698b8f7a..3537b62c76e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
@@ -399,16 +399,12 @@ static Array<float> calc_full_density_factors_with_selection(const MeshComponent
   GeometryComponentFieldContext field_context{component, attribute_domain};
   const int domain_size = component.attribute_domain_size(attribute_domain);
 
-  fn::FieldEvaluator selection_evaluator{field_context, domain_size};
-  selection_evaluator.add(selection_field);
-  selection_evaluator.evaluate();
-  const IndexMask selection_mask = selection_evaluator.get_evaluated_as_mask(0);
-
   Array<float> densities(domain_size, 0.0f);
 
-  fn::FieldEvaluator density_evaluator{field_context, &selection_mask};
-  density_evaluator.add_with_destination(density_field, densities.as_mutable_span());
-  density_evaluator.evaluate();
+  fn::FieldEvaluator evaluator{field_context, domain_size};
+  evaluator.set_selection(selection_field);
+  evaluator.add_with_destination(density_field, densities.as_mutable_span());
+  evaluator.evaluate();
   return densities;
 }
 
diff --git a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
index 6a661020bd9..486f90760f5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
@@ -65,12 +65,24 @@ static void add_instances_from_component(
   const AttributeDomain domain = ATTR_DOMAIN_POINT;
   const int domain_size = src_component.attribute_domain_size(domain);
 
+  VArray<bool> pick_instance;
+  VArray<int> indices;
+  VArray<float3> rotations;
+  VArray<float3> scales;
+
   GeometryComponentFieldContext field_context{src_component, domain};
   const Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
-  fn::FieldEvaluator selection_evaluator{field_context, domain_size};
-  selection_evaluator.add(selection_field);
-  selection_evaluator.evaluate();
-  const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+  fn::FieldEvaluator evaluator{field_context, domain_size};
+  evaluator.set_selection(selection_field);
+  /* The evaluator could use the component's stable IDs as a destination directly, but only the
+   * selected indices should be copied. */
+  evaluator.add(params.get_input<Field<bool>>("Pick Instance"), &pick_instance);
+  evaluator.add(params.get_input<Field<int>>("Instance Index"), &indices);
+  evaluator.add(params.get_input<Field<float3>>("Rotation"), &rotations);
+  evaluator.add(params.get_input<Field<float3>>("Scale"), &scales);
+  evaluator.evaluate();
+
+  const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
 
   /* The initial size of the component might be non-zero when this function is called for multiple
    * component types. */
@@ -83,19 +95,6 @@ static void add_instances_from_component(
   MutableSpan<float4x4> dst_transforms = dst_component.instance_transforms().slice(start_len,
                                                                                    select_len);
 
-  FieldEvaluator field_evaluator{field_context, domain_size};
-  VArray<bool> pick_instance;
-  VArray<int> indices;
-  VArray<float3> rotations;
-  VArray<float3> scales;
-  /* The evaluator could use the component's stable IDs as a destination directly, but only the
-   * selected indices should be copied. */
-  field_evaluator.add(params.get_input<Field<bool>>("Pick Instance"), &pick_instance);
-  field_evaluator.add(params.get_input<Field<int>>("Instance Index"), &indices);
-  field_evaluator.add(params.get_input<Field<float3>>("Rotation"), &rotations);
-  field_evaluator.add(params.get_input<Field<float3>>("Scale"), &scales);
-  field_evaluator.evaluate();
-
   VArray<float3> positions = src_component.attribute_get_for_read<float3>(
       "position", domain, {0, 0, 0});
 
diff --git a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
index 8dc5b4cc7b9..9942e388ba5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
@@ -56,10 +56,12 @@ static void convert_instances_to_points(GeometrySet &geometry_set,
   GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE};
   const int domain_size = instances.attribute_domain_size(ATTR_DOMAIN_INSTANCE);
 
-  fn::FieldEvaluator selection_evaluator{field_context, domain_size};
-  selection_evaluator.add(std::move(selection_field));
-  selection_evaluator.evaluate();
-  const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+  fn::FieldEvaluator evaluator{field_context, domain_size};
+  evaluator.set_selection(std::move(selection_field));
+  evaluator.add(std::move(position_field));
+  evaluator.add(std::move(radius_field));
+  evaluator.evaluate();
+  const IndexMask selection = evaluator.get_evaluated_selection_

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list