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:
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh4
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.cc46
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh1
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc27
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc21
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc22
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc29
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc24
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc21
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc30
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc41
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc27
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc5
-rw-r--r--source/blender/nodes/intern/node_geometry_exec.cc36
16 files changed, 310 insertions, 46 deletions
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index 91d46e3951f..222aa559e8a 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -222,6 +222,10 @@ class GeoNodeExecParams {
const GeometryComponent &component,
const CustomDataType default_type) const;
+ AttributeDomain get_highest_priority_input_domain(Span<std::string> names,
+ const GeometryComponent &component,
+ const AttributeDomain default_domain) const;
+
private:
/* Utilities for detecting common errors at when using this class. */
void check_extract_input(StringRef identifier, const CPPType *requested_type = nullptr) const;
diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc
index 95c25795356..3e30658e056 100644
--- a/source/blender/nodes/geometry/node_geometry_util.cc
+++ b/source/blender/nodes/geometry/node_geometry_util.cc
@@ -338,6 +338,52 @@ CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_
return most_complex_type;
}
+/**
+ * \note Generally the order should mirror the order of the domains
+ * established in each component's ComponentAttributeProviders.
+ */
+static int attribute_domain_priority(const AttributeDomain domain)
+{
+ switch (domain) {
+#if 0
+ case ATTR_DOMAIN_CURVE:
+ return 0;
+#endif
+ case ATTR_DOMAIN_POLYGON:
+ return 1;
+ case ATTR_DOMAIN_EDGE:
+ return 2;
+ case ATTR_DOMAIN_POINT:
+ return 3;
+ case ATTR_DOMAIN_CORNER:
+ return 4;
+ default:
+ /* Domain not supported in nodes yet. */
+ BLI_assert(false);
+ return 0;
+ }
+}
+
+/**
+ * Domains with a higher "information density" have a higher priority, in order
+ * to choose a domain that will not lose data through domain conversion.
+ */
+AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains)
+{
+ int highest_priority = INT_MIN;
+ AttributeDomain highest_priority_domain = ATTR_DOMAIN_CORNER;
+
+ for (const AttributeDomain domain : domains) {
+ const int priority = attribute_domain_priority(domain);
+ if (priority > highest_priority) {
+ highest_priority = priority;
+ highest_priority_domain = domain;
+ }
+ }
+
+ return highest_priority_domain;
+}
+
} // namespace blender::nodes
bool geo_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index 7ca44d82a38..13a58be86f6 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -45,6 +45,7 @@ void update_attribute_input_socket_availabilities(bNode &node,
const bool name_is_available = true);
CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType>);
+AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains);
Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component,
const AttributeDomain domain);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
index fc5fb4c5488..0309fb83bd7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
@@ -42,27 +42,44 @@ static void geo_node_attribute_color_ramp_layout(uiLayout *layout,
namespace blender::nodes {
+static AttributeDomain get_result_domain(const GeometryComponent &component,
+ StringRef input_name,
+ StringRef result_name)
+{
+ /* Use the domain of the result attribute if it already exists. */
+ ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
+ if (result_attribute) {
+ return result_attribute->domain();
+ }
+
+ /* Otherwise use the input attribute's domain if it exists. */
+ ReadAttributePtr input_attribute = component.attribute_try_get_for_read(input_name);
+ if (input_attribute) {
+ return input_attribute->domain();
+ }
+
+ return ATTR_DOMAIN_POINT;
+}
+
static void execute_on_component(const GeoNodeExecParams &params, GeometryComponent &component)
{
const bNode &bnode = params.node();
NodeAttributeColorRamp *node_storage = (NodeAttributeColorRamp *)bnode.storage;
+ const std::string result_name = params.get_input<std::string>("Result");
+ const std::string input_name = params.get_input<std::string>("Attribute");
/* Always output a color attribute for now. We might want to allow users to customize.
* Using the type of an existing attribute could work, but does not have a real benefit
* currently. */
const CustomDataType result_type = CD_PROP_COLOR;
+ const AttributeDomain result_domain = get_result_domain(component, input_name, result_name);
- const std::string result_name = params.get_input<std::string>("Result");
- /* Once we support more domains at the user level, we have to decide how the result domain is
- * chosen. */
- const AttributeDomain result_domain = ATTR_DOMAIN_POINT;
OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
result_name, result_domain, result_type);
if (!attribute_result) {
return;
}
- const std::string input_name = params.get_input<std::string>("Attribute");
FloatReadAttribute attribute_in = component.attribute_get_for_read<float>(
input_name, result_domain, 0.0f);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc
index a231b4f9e92..5214d938fb1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc
@@ -69,14 +69,27 @@ static void geo_node_attribute_combine_xyz_update(bNodeTree *UNUSED(ntree), bNod
*node, "Z", (GeometryNodeAttributeInputMode)node_storage->input_type_z);
}
+static AttributeDomain get_result_domain(const GeometryComponent &component,
+ const GeoNodeExecParams &params,
+ StringRef result_name)
+{
+ /* Use the domain of the result attribute if it already exists. */
+ ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
+ if (result_attribute) {
+ return result_attribute->domain();
+ }
+
+ /* Otherwise use the highest priority domain from existing input attributes, or the default. */
+ return params.get_highest_priority_input_domain({"X", "Y", "Z"}, component, ATTR_DOMAIN_POINT);
+}
+
static void combine_attributes(GeometryComponent &component, const GeoNodeExecParams &params)
{
const std::string result_name = params.get_input<std::string>("Result");
- /* The result domain is always point for now. */
- const AttributeDomain result_domain = ATTR_DOMAIN_POINT;
if (result_name.empty()) {
return;
}
+ const AttributeDomain result_domain = get_result_domain(component, params, result_name);
OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
result_name, result_domain, CD_PROP_FLOAT3);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc
index ee97102de7b..a6cd0dd7779 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc
@@ -240,20 +240,31 @@ static CustomDataType get_data_type(GeometryComponent &component,
return CD_PROP_FLOAT;
}
+static AttributeDomain get_result_domain(const GeometryComponent &component,
+ const GeoNodeExecParams &params,
+ StringRef result_name)
+{
+ /* Use the domain of the result attribute if it already exists. */
+ ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
+ if (result_attribute) {
+ return result_attribute->domain();
+ }
+
+ /* Otherwise use the highest priority domain from existing input attributes, or the default. */
+ return params.get_highest_priority_input_domain({"A", "B"}, component, ATTR_DOMAIN_POINT);
+}
+
static void attribute_compare_calc(GeometryComponent &component, const GeoNodeExecParams &params)
{
const bNode &node = params.node();
NodeAttributeCompare *node_storage = (NodeAttributeCompare *)node.storage;
const FloatCompareOperation operation = static_cast<FloatCompareOperation>(
node_storage->operation);
+ const std::string result_name = params.get_input<std::string>("Result");
- /* The result type of this node is always float. */
const CustomDataType result_type = CD_PROP_BOOL;
- /* The result domain is always point for now. */
- const AttributeDomain result_domain = ATTR_DOMAIN_POINT;
+ const AttributeDomain result_domain = get_result_domain(component, params, result_name);
- /* Get result attribute first, in case it has to overwrite one of the existing attributes. */
- const std::string result_name = params.get_input<std::string>("Result");
OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
result_name, result_domain, result_type);
if (!attribute_result) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
index a5ac1926963..d2a7e40877f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
@@ -67,16 +67,32 @@ static void geo_node_attribute_fill_update(bNodeTree *UNUSED(ntree), bNode *node
namespace blender::nodes {
-static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams &params)
+static AttributeDomain get_result_domain(const GeometryComponent &component,
+ const GeoNodeExecParams &params,
+ StringRef attribute_name)
{
+ /* Use the domain of the result attribute if it already exists. */
+ ReadAttributePtr result_attribute = component.attribute_try_get_for_read(attribute_name);
+ if (result_attribute) {
+ return result_attribute->domain();
+ }
+
+ /* Otherwise use the input domain chosen in the interface. */
const bNode &node = params.node();
- const CustomDataType data_type = static_cast<CustomDataType>(node.custom1);
- const AttributeDomain domain = static_cast<AttributeDomain>(node.custom2);
+ return static_cast<AttributeDomain>(node.custom2);
+}
+
+static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams &params)
+{
const std::string attribute_name = params.get_input<std::string>("Attribute");
if (attribute_name.empty()) {
return;
}
+ const bNode &node = params.node();
+ const CustomDataType data_type = static_cast<CustomDataType>(node.custom1);
+ const AttributeDomain domain = get_result_domain(component, params, attribute_name);
+
OutputAttributePtr attribute = component.attribute_try_get_for_output(
attribute_name, domain, data_type);
if (!attribute) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
index 1780ec69df2..17718949de3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
@@ -202,19 +202,40 @@ static void do_math_operation(Span<float> span_input,
UNUSED_VARS_NDEBUG(success);
}
+static AttributeDomain get_result_domain(const GeometryComponent &component,
+ const GeoNodeExecParams &params,
+ const NodeMathOperation operation,
+ StringRef result_name)
+{
+ /* Use the domain of the result attribute if it already exists. */
+ ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
+ if (result_attribute) {
+ return result_attribute->domain();
+ }
+
+ /* Otherwise use the highest priority domain from existing input attributes, or the default. */
+ const AttributeDomain default_domain = ATTR_DOMAIN_POINT;
+ if (operation_use_input_b(operation)) {
+ if (operation_use_input_c(operation)) {
+ return params.get_highest_priority_input_domain({"A", "B", "C"}, component, default_domain);
+ }
+ return params.get_highest_priority_input_domain({"A", "B"}, component, default_domain);
+ }
+ return params.get_highest_priority_input_domain({"A"}, component, default_domain);
+}
+
static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecParams &params)
{
const bNode &node = params.node();
const NodeAttributeMath *node_storage = (const NodeAttributeMath *)node.storage;
const NodeMathOperation operation = static_cast<NodeMathOperation>(node_storage->operation);
+ const std::string result_name = params.get_input<std::string>("Result");
/* The result type of this node is always float. */
const CustomDataType result_type = CD_PROP_FLOAT;
- /* The result domain is always point for now. */
- const AttributeDomain result_domain = ATTR_DOMAIN_POINT;
+ const AttributeDomain result_domain = get_result_domain(
+ component, params, operation, result_name);
- /* Get result attribute first, in case it has to overwrite one of the existing attributes. */
- const std::string result_name = params.get_input<std::string>("Result");
OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
result_name, result_domain, result_type);
if (!attribute_result) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc
index 2dbfcd2819c..e515f253a46 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc
@@ -125,10 +125,25 @@ static void do_mix_operation(const CustomDataType result_type,
}
}
+static AttributeDomain get_result_domain(const GeometryComponent &component,
+ const GeoNodeExecParams &params,
+ StringRef result_name)
+{
+ /* Use the domain of the result attribute if it already exists. */
+ ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
+ if (result_attribute) {
+ return result_attribute->domain();
+ }
+
+ /* Otherwise use the highest priority domain from existing input attributes, or the default. */
+ return params.get_highest_priority_input_domain({"A", "B"}, component, ATTR_DOMAIN_POINT);
+}
+
static void attribute_mix_calc(GeometryComponent &component, const GeoNodeExecParams &params)
{
const bNode &node = params.node();
const NodeAttributeMix *node_storage = (const NodeAttributeMix *)node.storage;
+ const std::string result_name = params.get_input<std::string>("Result");
/* Use the highest complexity data type among the inputs and outputs, that way the node will
* never "remove information". Use CD_PROP_BOOL as the lowest complexity data type, but in any
@@ -139,14 +154,7 @@ static void attribute_mix_calc(GeometryComponent &component, const GeoNodeExecPa
params.get_input_attribute_data_type("Result", component, CD_PROP_BOOL),
});
- /* Once we support more domains at the user level, we have to decide how the result domain is
- * chosen. */
- AttributeDomain result_domain = ATTR_DOMAIN_POINT;
- const std::string result_name = params.get_input<std::string>("Result");
- const ReadAttributePtr result_attribute_read = component.attribute_try_get_for_read(result_name);
- if (result_attribute_read) {
- result_domain = result_attribute_read->domain();
- }
+ const AttributeDomain result_domain = get_result_domain(component, params, result_name);
OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
result_name, result_domain, result_type);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
index e46fdaa127a..51f208ed07d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
@@ -148,9 +148,12 @@ static void attribute_calc_proximity(GeometryComponent &component,
GeometrySet &geometry_set_target,
GeoNodeExecParams &params)
{
+ /* This node works on the "point" domain, since that is where positions are stored. */
+ const AttributeDomain result_domain = ATTR_DOMAIN_POINT;
+
const std::string result_attribute_name = params.get_input<std::string>("Result");
OutputAttributePtr distance_attribute = component.attribute_try_get_for_output(
- result_attribute_name, ATTR_DOMAIN_POINT, CD_PROP_FLOAT);
+ result_attribute_name, result_domain, CD_PROP_FLOAT);
ReadAttributePtr position_attribute = component.attribute_try_get_for_read("position");
BLI_assert(position_attribute->custom_data_type() == CD_PROP_FLOAT3);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
index f4399b45b2e..7e95714a44b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
@@ -153,17 +153,32 @@ Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &compo
return hashes;
}
+static AttributeDomain get_result_domain(const GeometryComponent &component,
+ const GeoNodeExecParams &params,
+ StringRef attribute_name)
+{
+ /* Use the domain of the result attribute if it already exists. */
+ ReadAttributePtr result_attribute = component.attribute_try_get_for_read(attribute_name);
+ if (result_attribute) {
+ return result_attribute->domain();
+ }
+
+ /* Otherwise use the input domain chosen in the interface. */
+ const bNode &node = params.node();
+ return static_cast<AttributeDomain>(node.custom2);
+}
+
static void randomize_attribute(GeometryComponent &component,
const GeoNodeExecParams &params,
const int seed)
{
- const bNode &node = params.node();
- const CustomDataType data_type = static_cast<CustomDataType>(node.custom1);
- const AttributeDomain domain = static_cast<AttributeDomain>(node.custom2);
const std::string attribute_name = params.get_input<std::string>("Attribute");
if (attribute_name.empty()) {
return;
}
+ const bNode &node = params.node();
+ const CustomDataType data_type = static_cast<CustomDataType>(node.custom1);
+ const AttributeDomain domain = get_result_domain(component, params, attribute_name);
OutputAttributePtr attribute = component.attribute_try_get_for_output(
attribute_name, domain, data_type);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
index fc3cd099d41..dd8f0adb740 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
@@ -48,29 +48,51 @@ static void geo_node_attribute_sample_texture_layout(uiLayout *layout,
namespace blender::nodes {
+static AttributeDomain get_result_domain(const GeometryComponent &component,
+ StringRef result_attribute_name,
+ StringRef map_attribute_name)
+{
+ /* Use the domain of the result attribute if it already exists. */
+ ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_attribute_name);
+ if (result_attribute) {
+ return result_attribute->domain();
+ }
+
+ /* Otherwise use the name of the map attribute. */
+ ReadAttributePtr map_attribute = component.attribute_try_get_for_read(map_attribute_name);
+ if (map_attribute) {
+ return map_attribute->domain();
+ }
+
+ /* The node won't execute in this case, but we still have to return a value. */
+ return ATTR_DOMAIN_POINT;
+}
+
static void execute_on_component(GeometryComponent &component, const GeoNodeExecParams &params)
{
const bNode &node = params.node();
Tex *texture = reinterpret_cast<Tex *>(node.id);
- const std::string result_attribute_name = params.get_input<std::string>("Result");
-
if (texture == nullptr) {
return;
}
+ const std::string result_attribute_name = params.get_input<std::string>("Result");
const std::string mapping_name = params.get_input<std::string>("Mapping");
if (!component.attribute_exists(mapping_name)) {
return;
}
+ const AttributeDomain result_domain = get_result_domain(
+ component, result_attribute_name, mapping_name);
+
OutputAttributePtr attribute_out = component.attribute_try_get_for_output(
- result_attribute_name, ATTR_DOMAIN_POINT, CD_PROP_COLOR);
+ result_attribute_name, result_domain, CD_PROP_COLOR);
if (!attribute_out) {
return;
}
Float3ReadAttribute mapping_attribute = component.attribute_get_for_read<float3>(
- mapping_name, ATTR_DOMAIN_POINT, {0, 0, 0});
+ mapping_name, result_domain, {0, 0, 0});
MutableSpan<Color4f> colors = attribute_out->get_span<Color4f>();
for (const int i : IndexRange(mapping_attribute.size())) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc
index 07941f7db79..2e02ad9836d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc
@@ -69,22 +69,49 @@ static void extract_input(const int index, const Span<float3> &input, MutableSpa
}
}
+static AttributeDomain get_result_domain(const GeometryComponent &component,
+ const GeoNodeExecParams &params,
+ StringRef result_name_x,
+ StringRef result_name_y,
+ StringRef result_name_z)
+{
+ /* Use the highest priority domain from any existing attribute outputs. */
+ Vector<AttributeDomain, 3> output_domains;
+ ReadAttributePtr attribute_x = component.attribute_try_get_for_read(result_name_x);
+ ReadAttributePtr attribute_y = component.attribute_try_get_for_read(result_name_y);
+ ReadAttributePtr attribute_z = component.attribute_try_get_for_read(result_name_z);
+ if (attribute_x) {
+ output_domains.append(attribute_x->domain());
+ }
+ if (attribute_y) {
+ output_domains.append(attribute_y->domain());
+ }
+ if (attribute_z) {
+ output_domains.append(attribute_z->domain());
+ }
+ if (output_domains.size() > 0) {
+ return attribute_domain_highest_priority(output_domains);
+ }
+
+ /* Otherwise use the domain of the input attribute, or the default. */
+ return params.get_highest_priority_input_domain({"Vector"}, component, ATTR_DOMAIN_POINT);
+}
+
static void separate_attribute(GeometryComponent &component, const GeoNodeExecParams &params)
{
const std::string result_name_x = params.get_input<std::string>("Result X");
const std::string result_name_y = params.get_input<std::string>("Result Y");
const std::string result_name_z = params.get_input<std::string>("Result Z");
- /* The node is only for float3 to float conversions. */
- const CustomDataType input_type = CD_PROP_FLOAT3;
- const CustomDataType result_type = CD_PROP_FLOAT;
- /* The result domain is always point for now. */
- const AttributeDomain result_domain = ATTR_DOMAIN_POINT;
-
- /* No output to write to. */
if (result_name_x.empty() && result_name_y.empty() && result_name_z.empty()) {
return;
}
+ /* The node is only for float3 to float conversions. */
+ const CustomDataType input_type = CD_PROP_FLOAT3;
+ const CustomDataType result_type = CD_PROP_FLOAT;
+ const AttributeDomain result_domain = get_result_domain(
+ component, params, result_name_x, result_name_y, result_name_z);
+
ReadAttributePtr attribute_input = params.get_input_attribute(
"Vector", component, result_domain, input_type, nullptr);
if (!attribute_input) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc
index adcdab58e30..45b28d154f4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc
@@ -327,12 +327,35 @@ static void do_math_operation_fl3_to_fl(const Float3ReadAttribute &input_a,
UNUSED_VARS_NDEBUG(success);
}
+static AttributeDomain get_result_domain(const GeometryComponent &component,
+ const GeoNodeExecParams &params,
+ const NodeVectorMathOperation operation,
+ StringRef result_name)
+{
+ /* Use the domain of the result attribute if it already exists. */
+ ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
+ if (result_attribute) {
+ return result_attribute->domain();
+ }
+
+ /* Otherwise use the highest priority domain from existing input attributes, or the default. */
+ const AttributeDomain default_domain = ATTR_DOMAIN_POINT;
+ if (operation_use_input_b(operation)) {
+ if (operation_use_input_c(operation)) {
+ return params.get_highest_priority_input_domain({"A", "B", "C"}, component, default_domain);
+ }
+ return params.get_highest_priority_input_domain({"A", "B"}, component, default_domain);
+ }
+ return params.get_highest_priority_input_domain({"A"}, component, default_domain);
+}
+
static void attribute_vector_math_calc(GeometryComponent &component,
const GeoNodeExecParams &params)
{
const bNode &node = params.node();
const NodeAttributeVectorMath *node_storage = (const NodeAttributeVectorMath *)node.storage;
const NodeVectorMathOperation operation = (NodeVectorMathOperation)node_storage->operation;
+ const std::string result_name = params.get_input<std::string>("Result");
/* The number and type of the input attribute depend on the operation. */
const CustomDataType read_type_a = CD_PROP_FLOAT3;
@@ -343,7 +366,8 @@ static void attribute_vector_math_calc(GeometryComponent &component,
/* The result domain is always point for now. */
const CustomDataType result_type = operation_get_result_type(operation);
- const AttributeDomain result_domain = ATTR_DOMAIN_POINT;
+ const AttributeDomain result_domain = get_result_domain(
+ component, params, operation, result_name);
ReadAttributePtr attribute_a = params.get_input_attribute(
"A", component, result_domain, read_type_a, nullptr);
@@ -366,7 +390,6 @@ static void attribute_vector_math_calc(GeometryComponent &component,
}
/* Get result attribute first, in case it has to overwrite one of the existing attributes. */
- const std::string result_name = params.get_input<std::string>("Result");
OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
result_name, result_domain, result_type);
if (!attribute_result) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
index ca2e1be6e6f..4fec14ec9c9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -147,16 +147,17 @@ static void determine_final_data_type_and_domain(Span<const GeometryComponent *>
AttributeDomain *r_domain)
{
Vector<CustomDataType> data_types;
+ Vector<AttributeDomain> domains;
for (const GeometryComponent *component : components) {
ReadAttributePtr attribute = component->attribute_try_get_for_read(attribute_name);
if (attribute) {
data_types.append(attribute->custom_data_type());
- /* TODO: Use highest priority domain. */
- *r_domain = attribute->domain();
+ domains.append(attribute->domain());
}
}
*r_type = attribute_data_type_highest_complexity(data_types);
+ *r_domain = attribute_domain_highest_priority(domains);
}
static void fill_new_attribute(Span<const GeometryComponent *> src_components,
diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc
index eef2c6c9125..6ddeb73e31f 100644
--- a/source/blender/nodes/intern/node_geometry_exec.cc
+++ b/source/blender/nodes/intern/node_geometry_exec.cc
@@ -17,6 +17,8 @@
#include "NOD_geometry_exec.hh"
#include "NOD_type_callbacks.hh"
+#include "node_geometry_util.hh"
+
namespace blender::nodes {
const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const
@@ -104,6 +106,40 @@ CustomDataType GeoNodeExecParams::get_input_attribute_data_type(
return default_type;
}
+/**
+ * If any of the corresponding input sockets are attributes instead of single values,
+ * use the highest priority attribute domain from among them.
+ * Otherwise return the default domain.
+ */
+AttributeDomain GeoNodeExecParams::get_highest_priority_input_domain(
+ Span<std::string> names,
+ const GeometryComponent &component,
+ const AttributeDomain default_domain) const
+{
+ Vector<AttributeDomain, 8> input_domains;
+ for (const std::string &name : names) {
+ const bNodeSocket *found_socket = this->find_available_socket(name);
+ BLI_assert(found_socket != nullptr); /* A socket should be available socket for the name. */
+ if (found_socket == nullptr) {
+ continue;
+ }
+
+ if (found_socket->type == SOCK_STRING) {
+ const std::string name = this->get_input<std::string>(found_socket->identifier);
+ ReadAttributePtr attribute = component.attribute_try_get_for_read(name);
+ if (attribute) {
+ input_domains.append(attribute->domain());
+ }
+ }
+ }
+
+ if (input_domains.size() > 0) {
+ return attribute_domain_highest_priority(input_domains);
+ }
+
+ return default_domain;
+}
+
void GeoNodeExecParams::check_extract_input(StringRef identifier,
const CPPType *requested_type) const
{