[Bf-blender-cvs] [d7c2c889a68] master: Geometry Nodes: Allow attribute nodes to use different domains

Hans Goudey noreply at git.blender.org
Fri Feb 12 19:46:25 CET 2021


Commit: d7c2c889a688067dab280fc137ad4c3c7ce4cb2b
Author: Hans Goudey
Date:   Fri Feb 12 12:46:17 2021 -0600
Branches: master
https://developer.blender.org/rBd7c2c889a688067dab280fc137ad4c3c7ce4cb2b

Geometry Nodes: Allow attribute nodes to use different domains

Currently every attribute node assumes that the attribute exists on the
"points" domain, so it generally isn't possible to work with attributes
on other domains like edges, polygons, and corners.

This commit adds a heuristic to each attribute node to determine the
correct domain for the result attribute. In general, it works like this:
 - If the output attribute already exists, use that domain.
 - Otherwise, use the highest priority domain of the input attributes.
 - If none of the inputs are attributes, use the default domain (points).

For the implementation I abstracted the check a bit, but in each
node has a slightly different situation, so we end up with slightly
different `get_result_domain` functions in each node. I think this makes
sense, it keeps the code flexible and more easily understandable.

Note that we might eventually want to expose a domain drop-down to some
of the nodes. But that will be a separate discussion; this commit focuses
on making a more useful choice automatically.

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

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

M	source/blender/nodes/NOD_geometry_exec.hh
M	source/blender/nodes/geometry/node_geometry_util.cc
M	source/blender/nodes/geometry/node_geometry_util.hh
M	source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
M	source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc
M	source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc
M	source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
M	source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
M	source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc
M	source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
M	source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
M	source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
M	source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc
M	source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc
M	source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
M	source/blender/nodes/intern/node_geometry_exec.cc

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

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(bNodeTre

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list