[Bf-blender-cvs] [62f8bb87b79] temp-geometry-nodes-fields: Add utility methods for field destinations and selection fields

Hans Goudey noreply at git.blender.org
Fri Sep 3 20:07:01 CEST 2021


Commit: 62f8bb87b791da2ce64098c118699ca3f7696d92
Author: Hans Goudey
Date:   Fri Sep 3 13:06:54 2021 -0500
Branches: temp-geometry-nodes-fields
https://developer.blender.org/rB62f8bb87b791da2ce64098c118699ca3f7696d92

Add utility methods for field destinations and selection fields

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

M	source/blender/functions/FN_field.hh
M	source/blender/functions/intern/field.cc
M	source/blender/nodes/geometry/nodes/node_geo_set_position.cc

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

diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh
index 2262bfdb641..81c18b2dc54 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -142,7 +142,8 @@ class GField : public GFieldBase<std::shared_ptr<FieldNode>> {
   }
 };
 
-/** Same as #GField but is cheaper to copy/move around, because it does not contain a
+/**
+ * Same as #GField but is cheaper to copy/move around, because it does not contain a
  * #std::shared_ptr.
  */
 class GFieldRef : public GFieldBase<const FieldNode *> {
@@ -287,6 +288,8 @@ void evaluate_fields_to_spans(Span<GFieldRef> fields_to_evaluate,
                               const FieldContext &context,
                               Span<GMutableSpan> out_spans);
 
+Vector<int64_t> indices_from_selection(const VArray<bool> &selection);
+
 template<typename T> T evaluate_constant_field(const Field<T> &field)
 {
   T value;
@@ -326,6 +329,9 @@ class FieldEvaluator : NonMovable, NonCopyable {
       : context_(context), mask_(*mask)
   {
   }
+  FieldEvaluator(const FieldContext &context, const int64_t size) : context_(context), mask_(size)
+  {
+  }
 
   /**
    * \param field: Field to add to the evaluator.
@@ -347,6 +353,34 @@ class FieldEvaluator : NonMovable, NonCopyable {
     return this->add_with_destination(GField(std::move(field)), generic_dst_hint);
   }
 
+  /**
+   * \param field: Field to add to the evaluator.
+   * \param dst: Mutable span that the evaluated result for this field is be written into.
+   * \note: When the output may only be used as a single value, the version of this function with
+   * a virtual array result array should be used.
+   */
+  int add_with_destination(GField field, GMutableSpan dst)
+  {
+    const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
+    dst_hints_.append(&scope_.construct<GVMutableArray_For_GMutableSpan>(__func__, dst));
+    output_pointer_infos_.append({});
+    return field_index;
+  }
+
+  /**
+   * \param field: Field to add to the evaluator.
+   * \param dst: Mutable span that the evaluated result for this field is be written into.
+   * \note: When the output may only be used as a single value, the version of this function with
+   * a virtual array result array should be used.
+   */
+  template<typename T> int add_with_destination(Field<T> field, MutableSpan<T> dst)
+  {
+    const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
+    dst_hints_.append(&scope_.construct<GVMutableArray_For_MutableSpan<T>>(__func__, dst));
+    output_pointer_infos_.append({});
+    return field_index;
+  }
+
   int add(GField field, const GVArray **varray_ptr)
   {
     const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field));
@@ -419,6 +453,26 @@ class FieldEvaluator : NonMovable, NonCopyable {
     GVArray_Typed<T> &typed_varray = scope_.construct<GVArray_Typed<T>>(__func__, varray);
     return *typed_varray;
   }
+
+  /**
+   * 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
+   * some cases, so it must live at least as long as the returned mask.
+   */
+  IndexMask get_evaluated_as_mask(const int field_index)
+  {
+    const GVArray &varray = this->get_evaluated(field_index);
+    GVArray_Typed<bool> typed_varray{varray};
+
+    if (typed_varray->is_single()) {
+      if (typed_varray->get_internal_single()) {
+        return IndexRange(typed_varray.size());
+      }
+      return IndexRange(0);
+    }
+
+    return scope_.add_value(indices_from_selection(*typed_varray), __func__).as_span();
+  }
 };
 
 }  // namespace blender::fn
diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc
index f10a154dcd6..97c3b0b368e 100644
--- a/source/blender/functions/intern/field.cc
+++ b/source/blender/functions/intern/field.cc
@@ -32,8 +32,8 @@ struct FieldTreeInfo {
    */
   MultiValueMap<GFieldRef, GFieldRef> field_users;
   /**
-   * The same field input may exist in the field tree as as separate nodes due to the way the tree
-   * is constructed. This set contains every input only once.
+   * The same field input may exist in the field tree as as separate nodes due to the way
+   * the tree is constructed. This set contains every different input only once.
    */
   VectorSet<std::reference_wrapper<const FieldInput>> deduplicated_field_inputs;
 };
@@ -205,8 +205,8 @@ static void build_multi_function_procedure_for_fields(MFProcedure &procedure,
   for (const GFieldRef &field : output_fields) {
     MFVariable *variable = variable_by_field.lookup(field);
     if (!already_output_variables.add(variable)) {
-      /* One variable can be output at most once. To output the same value twice, we have to make a
-       * copy first. */
+      /* One variable can be output at most once. To output the same value twice, we have to make
+       * a copy first. */
       const MultiFunction &copy_fn = scope.construct<CustomMF_GenericCopy>(
           __func__, "copy", variable->data_type());
       variable = builder.add_call<1>(copy_fn, {variable})[0];
@@ -258,7 +258,7 @@ struct PartiallyInitializedArray : NonCopyable, NonMovable {
  *   instead of into newly created ones. That allows making the computed data live longer than
  *   #scope and is more efficient when the data will be written into those virtual arrays
  *   later anyway.
- * \return The computed virtual arrays for each provided field. If #dst_hints were passed, the
+ * \return The computed virtual arrays for each provided field. If #dst_hints is passed, the
  *   provided virtual arrays are returned.
  */
 Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
@@ -284,7 +284,7 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
   Vector<const GVArray *> field_context_inputs = get_field_context_inputs(
       scope, mask, context, field_tree_info.deduplicated_field_inputs);
 
-  /* Finish fields that output a context varray directly. For those we don't have to do any further
+  /* Finish fields that output an input varray directly. For those we don't have to do any further
    * processing. */
   for (const int out_index : fields_to_evaluate.index_range()) {
     const GFieldRef &field = fields_to_evaluate[out_index];
@@ -330,7 +330,7 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
     build_multi_function_procedure_for_fields(
         procedure, scope, field_tree_info, varying_fields_to_evaluate);
     MFProcedureExecutor procedure_executor{"Procedure", procedure};
-    MFParamsBuilder mf_params{procedure_executor, mask.min_array_size()};
+    MFParamsBuilder mf_params{procedure_executor, array_size};
     MFContextBuilder mf_context;
 
     /* Provide inputs to the procedure executor. */
@@ -480,4 +480,28 @@ const GVArray *FieldContext::try_get_varray_for_context(const FieldInput &field_
   return field_input.try_get_varray_for_context(*this, mask, scope);
 }
 
+Vector<int64_t> indices_from_selection(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. */
+  BLI_assert(!selection.is_single());
+  Vector<int64_t> indices;
+  if (selection.is_span()) {
+    Span<bool> span = selection.get_internal_span();
+    for (const int64_t i : span.index_range()) {
+      if (span[i]) {
+        indices.append(i);
+      }
+    }
+  }
+  else {
+    for (const int i : selection.index_range()) {
+      if (selection[i]) {
+        indices.append(i);
+      }
+    }
+  }
+  return indices;
+}
+
 }  // namespace blender::fn
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
index eb48186e326..e8591616f55 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
@@ -28,55 +28,24 @@ static void geo_node_set_position_declare(NodeDeclarationBuilder &b)
   b.add_output<decl::Geometry>("Geometry");
 }
 
-static IndexMask index_mask_from_selection_varray(const VArray<bool> &selection,
-                                                  Vector<int64_t> &r_indices)
-{
-  if (selection.is_single()) {
-    if (selection.get_internal_single()) {
-      return IndexRange(selection.size());
-    }
-    return IndexRange(0);
-  }
-  if (selection.is_span()) {
-    Span<bool> selection_span = selection.get_internal_span();
-    for (const int i : selection_span.index_range()) {
-      if (selection_span[i]) {
-        r_indices.append(i);
-      }
-    }
-  }
-  else {
-    for (const int i : selection.index_range()) {
-      if (selection[i]) {
-        r_indices.append(i);
-      }
-    }
-  }
-  return r_indices.as_span();
-}
-
 static void set_position_in_component(GeometryComponent &component,
                                       const Field<bool> &selection_field,
                                       const Field<float3> &position_field)
 {
   GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
   const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
-  const IndexMask full_mask{IndexRange(domain_size)};
 
-  fn::FieldEvaluator selection_evaluator{field_context, &full_mask};
-  const VArray<bool> *selection = nullptr;
-  selection_evaluator.add(selection_field, &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);
 
-  Vector<int64_t> mask_indices;
-  const IndexMask selected_mask = index_mask_from_selection_varray(*selection, mask_indices);
-
-  OutputAttribute_Typed<float3> position_attribute =
-      component.attribute_try_get_for_output<float3>("position", ATTR_DOMAIN_POINT, {0, 0, 0});
-  fn::FieldEvaluator position_evaluator{field_context, &selected_mask};
-  position_evaluator.add_with_destination(position_field, position_att

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list