Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohnny Matthews <johnny.matthews@gmail.com>2021-12-15 17:04:49 +0300
committerJohnny Matthews <johnny.matthews@gmail.com>2021-12-15 17:04:49 +0300
commit1a833dbdb9c4ec4e19fcd900b1a98a89d1d95a8c (patch)
tree0d17fc45711ed9226093c63c3ce02e6eb664186b /source/blender/nodes
parente85d7d5a2880c3e9721eafa5a72ce249c5f131f7 (diff)
Geometry Nodes: Add Selection to Attribute Statistics
This adds a bool field selection input to the Attribute Statistics node. This is useful for running calculations on a subset of the input field data rather that then whole set. Differential Revision: https://developer.blender.org/D13520
Diffstat (limited to 'source/blender/nodes')
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc70
1 files changed, 39 insertions, 31 deletions
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
index 4d7ab97bf0e..c754f70d323 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
@@ -29,6 +29,7 @@ namespace blender::nodes::node_geo_attribute_statistic_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
b.add_input<decl::Float>(N_("Attribute")).hide_value().supports_field();
b.add_input<decl::Vector>(N_("Attribute"), "Attribute_001").hide_value().supports_field();
@@ -66,7 +67,8 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *socket_geo = (bNodeSocket *)node->inputs.first;
- bNodeSocket *socket_float_attr = socket_geo->next;
+ bNodeSocket *socket_selection = socket_geo->next;
+ bNodeSocket *socket_float_attr = socket_selection->next;
bNodeSocket *socket_float3_attr = socket_float_attr->next;
bNodeSocket *socket_float_mean = (bNodeSocket *)node->outputs.first;
@@ -148,38 +150,36 @@ static float median_of_sorted_span(const Span<float> data)
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.get_input<GeometrySet>("Geometry");
-
const bNode &node = params.node();
const CustomDataType data_type = static_cast<CustomDataType>(node.custom1);
const AttributeDomain domain = static_cast<AttributeDomain>(node.custom2);
-
- int64_t total_size = 0;
Vector<const GeometryComponent *> components = geometry_set.get_components_for_read();
- for (const GeometryComponent *component : components) {
- if (component->attribute_domain_supported(domain)) {
- total_size += component->attribute_domain_size(domain);
- }
- }
- if (total_size == 0) {
- params.set_default_remaining_outputs();
- return;
- }
+ const Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
switch (data_type) {
case CD_PROP_FLOAT: {
const Field<float> input_field = params.get_input<Field<float>>("Attribute");
- Array<float> data = Array<float>(total_size);
- int offset = 0;
+ Vector<float> data;
for (const GeometryComponent *component : components) {
if (component->attribute_domain_supported(domain)) {
GeometryComponentFieldContext field_context{*component, domain};
const int domain_size = component->attribute_domain_size(domain);
+
fn::FieldEvaluator data_evaluator{field_context, domain_size};
- MutableSpan<float> component_result = data.as_mutable_span().slice(offset, domain_size);
- data_evaluator.add_with_destination(input_field, component_result);
+ data_evaluator.add(input_field);
+ data_evaluator.set_selection(selection_field);
data_evaluator.evaluate();
- offset += domain_size;
+ const VArray<float> &component_data = data_evaluator.get_evaluated<float>(0);
+ const IndexMask selection = data_evaluator.get_evaluated_selection_as_mask();
+
+ const int next_data_index = data.size();
+ data.resize(next_data_index + selection.size());
+ MutableSpan<float> selected_data = data.as_mutable_span().slice(next_data_index,
+ selection.size());
+ for (const int i : selection.index_range()) {
+ selected_data[i] = component_data[selection[i]];
+ }
}
}
@@ -200,7 +200,7 @@ static void node_geo_exec(GeoNodeExecParams params)
const bool variance_required = params.output_is_required("Standard Deviation") ||
params.output_is_required("Variance");
- if (total_size != 0) {
+ if (data.size() != 0) {
if (sort_required) {
std::sort(data.begin(), data.end());
median = median_of_sorted_span(data);
@@ -211,7 +211,7 @@ static void node_geo_exec(GeoNodeExecParams params)
}
if (sum_required || variance_required) {
sum = compute_sum<float>(data);
- mean = sum / total_size;
+ mean = sum / data.size();
if (variance_required) {
variance = compute_variance(data, mean);
@@ -238,18 +238,26 @@ static void node_geo_exec(GeoNodeExecParams params)
}
case CD_PROP_FLOAT3: {
const Field<float3> input_field = params.get_input<Field<float3>>("Attribute_001");
-
- Array<float3> data = Array<float3>(total_size);
- int offset = 0;
+ Vector<float3> data;
for (const GeometryComponent *component : components) {
if (component->attribute_domain_supported(domain)) {
GeometryComponentFieldContext field_context{*component, domain};
const int domain_size = component->attribute_domain_size(domain);
+
fn::FieldEvaluator data_evaluator{field_context, domain_size};
- MutableSpan<float3> component_result = data.as_mutable_span().slice(offset, domain_size);
- data_evaluator.add_with_destination(input_field, component_result);
+ data_evaluator.add(input_field);
+ data_evaluator.set_selection(selection_field);
data_evaluator.evaluate();
- offset += domain_size;
+ const VArray<float3> &component_data = data_evaluator.get_evaluated<float3>(0);
+ const IndexMask selection = data_evaluator.get_evaluated_selection_as_mask();
+
+ const int next_data_index = data.size();
+ data.resize(data.size() + selection.size());
+ MutableSpan<float3> selected_data = data.as_mutable_span().slice(next_data_index,
+ selection.size());
+ for (const int i : selection.index_range()) {
+ selected_data[i] = component_data[selection[i]];
+ }
}
}
@@ -274,9 +282,9 @@ static void node_geo_exec(GeoNodeExecParams params)
Array<float> data_y;
Array<float> data_z;
if (sort_required || variance_required) {
- data_x.reinitialize(total_size);
- data_y.reinitialize(total_size);
- data_z.reinitialize(total_size);
+ data_x.reinitialize(data.size());
+ data_y.reinitialize(data.size());
+ data_z.reinitialize(data.size());
for (const int i : data.index_range()) {
data_x[i] = data[i].x;
data_y[i] = data[i].y;
@@ -284,7 +292,7 @@ static void node_geo_exec(GeoNodeExecParams params)
}
}
- if (total_size != 0) {
+ if (data.size() != 0) {
if (sort_required) {
std::sort(data_x.begin(), data_x.end());
std::sort(data_y.begin(), data_y.end());
@@ -301,7 +309,7 @@ static void node_geo_exec(GeoNodeExecParams params)
}
if (sum_required || variance_required) {
sum = compute_sum(data.as_span());
- mean = sum / total_size;
+ mean = sum / data.size();
if (variance_required) {
const float x_variance = compute_variance(data_x, mean.x);