[Bf-blender-cvs] [5f9a6ac183d] temp-gpu-image-engine: Geometry Nodes: simplify using selection when evaluating fields
Jacques Lucke
noreply at git.blender.org
Wed Dec 15 14:37:50 CET 2021
Commit: 5f9a6ac183dafa0c3cb2aad7604bc6f10917a0c2
Author: Jacques Lucke
Date: Tue Dec 14 15:40:16 2021 +0100
Branches: temp-gpu-image-engine
https://developer.blender.org/rB5f9a6ac183dafa0c3cb2aad7604bc6f10917a0c2
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