[Bf-blender-cvs] [0f8487f640e] master: Geometry Nodes: add more details about field handling to node declaration

Jacques Lucke noreply at git.blender.org
Tue Jan 3 12:24:19 CET 2023


Commit: 0f8487f640edd754de21cffec2dc6c9a1db7234c
Author: Jacques Lucke
Date:   Tue Jan 3 12:24:00 2023 +0100
Branches: master
https://developer.blender.org/rB0f8487f640edd754de21cffec2dc6c9a1db7234c

Geometry Nodes: add more details about field handling to node declaration

This is part of D16858 but is also useful for other purposes.

The changes to the node declaration in this commit allow us to figure
out which fields might be evaluated on which geometries statically (without
executing the node tree). This allows for deterministic anonymous attribute
handling, which will be committed separately. Furthermore, this is necessary
for usability features that help the user to avoid creating links that don't
make sense (e.g. because a field can't be evaluated on a certain geometry).
This also allows us to better separate fields which depend or don't depend
on anonymous attributes.

The main idea is that each node defines some relations between its sockets.
There are four relations:
* Propagate relation: Indicates that attributes on a geometry input can be
  propagated to a geometry output.
* Reference relation: Indicates that an output field references an inputs field.
  So if the input field depends on an anonymous attribute, the output field
  does as well.
* Eval relation: Indicates that an input field is evaluated on an input geometry.
* Available relation: Indicates that an output field has anonymous attributes
  that are available on an output geometry.

These relations can also be computed for node groups automatically, but that
is not part of this commit.

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

M	source/blender/nodes/NOD_node_declaration.hh
M	source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
M	source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
M	source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
M	source/blender/nodes/geometry/nodes/node_geo_blur_attribute.cc
M	source/blender/nodes/geometry/nodes/node_geo_boolean.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_set_handle_type.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_topology_curve_of_point.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_topology_points_of_curve.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
M	source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc
M	source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
M	source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc
M	source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
M	source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
M	source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
M	source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_curves.cc
M	source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_selection.cc
M	source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
M	source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
M	source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc
M	source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc
M	source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc
M	source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
M	source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.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_interpolate_domain.cc
M	source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
M	source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
M	source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_face.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_topology_vertex_of_corner.cc
M	source/blender/nodes/geometry/nodes/node_geo_offset_point_in_curve.cc
M	source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
M	source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
M	source/blender/nodes/geometry/nodes/node_geo_proximity.cc
M	source/blender/nodes/geometry/nodes/node_geo_raycast.cc
M	source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
M	source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc
M	source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
M	source/blender/nodes/geometry/nodes/node_geo_sample_index.cc
M	source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc
M	source/blender/nodes/geometry/nodes/node_geo_sample_uv_surface.cc
M	source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc
M	source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
M	source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
M	source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
M	source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
M	source/blender/nodes/geometry/nodes/node_geo_set_curve_normal.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.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_store_named_attribute.cc
M	source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
M	source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
M	source/blender/nodes/geometry/nodes/node_geo_switch.cc
M	source/blender/nodes/geometry/nodes/node_geo_transform_geometry.cc
M	source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
M	source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
M	source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc
M	source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc
M	source/blender/nodes/geometry/nodes/node_geo_viewer.cc
M	source/blender/nodes/intern/node_declaration.cc

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

diff --git a/source/blender/nodes/NOD_node_declaration.hh b/source/blender/nodes/NOD_node_declaration.hh
index 7753e8092d8..080f3e5e855 100644
--- a/source/blender/nodes/NOD_node_declaration.hh
+++ b/source/blender/nodes/NOD_node_declaration.hh
@@ -65,6 +65,76 @@ struct FieldInferencingInterface {
   Vector<OutputFieldDependency> outputs;
 };
 
+namespace anonymous_attribute_lifetime {
+
+/**
+ * Attributes can be propagated from an input geometry to an output geometry.
+ */
+struct PropagateRelation {
+  int from_geometry_input;
+  int to_geometry_output;
+
+  friend bool operator==(const PropagateRelation &a, const PropagateRelation &b)
+  {
+    return a.from_geometry_input == b.from_geometry_input &&
+           a.to_geometry_output == b.to_geometry_output;
+  }
+};
+
+/**
+ * References to attributes can be propagated from an input field to an output field.
+ */
+struct ReferenceRelation {
+  int from_field_input;
+  int to_field_output;
+
+  friend bool operator==(const ReferenceRelation &a, const ReferenceRelation &b)
+  {
+    return a.from_field_input == b.from_field_input && a.to_field_output == b.to_field_output;
+  }
+};
+
+/**
+ * An input field is evaluated on an input geometry.
+ */
+struct EvalRelation {
+  int field_input;
+  int geometry_input;
+
+  friend bool operator==(const EvalRelation &a, const EvalRelation &b)
+  {
+    return a.field_input == b.field_input && a.geometry_input == b.geometry_input;
+  }
+};
+
+/**
+ * An output field is available on an output geometry.
+ */
+struct AvailableRelation {
+  int field_output;
+  int geometry_output;
+
+  friend bool operator==(const AvailableRelation &a, const AvailableRelation &b)
+  {
+    return a.field_output == b.field_output && a.geometry_output == b.geometry_output;
+  }
+};
+
+struct RelationsInNode {
+  Vector<PropagateRelation> propagate_relations;
+  Vector<ReferenceRelation> reference_relations;
+  Vector<EvalRelation> eval_relations;
+  Vector<AvailableRelation> available_relations;
+  Vector<int> available_on_none;
+};
+
+bool operator==(const RelationsInNode &a, const RelationsInNode &b);
+bool operator!=(const RelationsInNode &a, const RelationsInNode &b);
+std::ostream &operator<<(std::ostream &stream, const RelationsInNode &relations);
+
+}  // namespace anonymous_attribute_lifetime
+namespace aal = anonymous_attribute_lifetime;
+
 using ImplicitInputValueFn = std::function<void(const bNode &node, void *r_value)>;
 
 /**
@@ -146,9 +216,23 @@ class SocketDeclaration {
   bool matches_common_data(const bNodeSocket &socket) const;
 };
 
+class NodeDeclarationBuilder;
+
 class BaseSocketDeclarationBuilder {
+ protected:
+  int index_ = -1;
+  bool reference_pass_all_ = false;
+  bool field_on_all_ = false;
+  bool propagate_from_all_ = false;
+  NodeDeclarationBuilder *node_decl_builder_ = nullptr;
+
+  friend class NodeDeclarationBuilder;
+
  public:
   virtual ~BaseSocketDeclarationBuilder() = default;
+
+ protected:
+  virtual SocketDeclaration *declaration() = 0;
 };
 
 /**
@@ -225,6 +309,26 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
     return *(Self *)this;
   }
 
+  /**
+   * For inputs this means that the input field is evaluated on all geometry inputs. For outputs
+   * it means that this contains an anonymous attribute reference that is available on all geometry
+   * outputs.
+   */
+  Self &field_on_all()
+  {
+    if (decl_->in_out == SOCK_IN) {
+      this->supports_field();
+    }
+    else {
+      this->field_source();
+    }
+    field_on_all_ = true;
+    return *(Self *)this;
+  }
+
+  /** For inputs that are evaluated or available on a subset of the geometry sockets. */
+  Self &field_on(Span<int> indices);
+
   /** The input supports a field and is a field by default when nothing is connected. */
   Self &implicit_field(ImplicitInputValueFn fn)
   {
@@ -234,6 +338,22 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
     return *(Self *)this;
   }
 
+  /** The input is an implicit field that is evaluated on all geometry inputs. */
+  Self &implicit_field_on_all(ImplicitInputValueFn fn)
+  {
+    this->implicit_field(fn);
+    field_on_all_ = true;
+    return *(Self *)this;
+  }
+
+  /** The input is evaluated on a subset of the geometry inputs. */
+  Self &implicit_field_on(ImplicitInputValueFn fn, const Span<int> input_indices)
+  {
+    this->implicit_field(fn);
+    this->field_on(input_indices);
+    return *(Self *)this;
+  }
+
   /** The output is always a field, regardless of any inputs. */
   Self &field_source()
   {
@@ -241,21 +361,55 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
     return *(Self *)this;
   }
 
-  /** The output is a field if any of the inputs is a field. */
+  /** The output is a field if any of the inputs are a field. */
   Self &dependent_field()
   {
     decl_->output_field_dependency = OutputFieldDependency::ForDependentField();
+    this->reference_pass_all();
     return *(Self *)this;
   }
 
   /** The output is a field if any of the inputs with indices in the given list is a field. */
   Self &dependent_field(Vector<int> input_dependencies)
   {
+    this->reference_pass(input_dependencies);
     decl_->output_field_dependency = OutputFieldDependency::ForPartiallyDependentField(
         std::move(input_dependencies));
     return *(Self *)this;
   }
 
+  /**
+   * For outputs that combine all input fields into a new field. The output is a field even if none
+   * of the inputs is a field.
+   */
+  Self &field_source_reference_all()
+  {
+    this->field_source();
+    this->reference_pass_all();
+    return *(Self *)this;
+  }
+
+  /**
+   * For outputs that combine a subset of input fields into a new field.
+   */
+  Self &reference_pass(Span<int> input_indices);
+
+  /**
+   * For outputs that combine all input fields into a new field.
+   */
+  Self &reference_pass_all()
+  {
+    reference_pass_all_ = true;
+    return *(Self *)this;
+  }
+
+  /** Attributes from the all geometry inputs can be propagated. */
+  Self &propagate_all()
+  {
+    propagate_from_all_ = true;
+    return *(Self *)this;
+  }
+
   /** The priority of the input for determining the domain of the node. See
    * realtime_compositor::InputDescriptor for more information. */
   Self &compositor_domain_priority(int priority)
@@ -291,6 +445,12 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
     decl_->make_available_fn_ = std::move(fn);
     return *(Self *)this;
   }
+
+ protected:
+  SocketDeclaration *declaration() override
+  {
+    return decl_;
+  }
 };
 
 using SocketDeclarationPtr = std::unique_ptr<SocketDeclaration>;
@@ -299,19 +459,26 @@ class NodeDeclaration {
  public:
   Vector<SocketDeclarationPtr> inputs;
   Vector<SocketDeclarationPtr> outputs;
+  std::unique_ptr<aal::RelationsInNode> anonymous_attribute_relations_;
 
   friend NodeDeclarationBuilder;
 
   bool matches(const bNode &node) const;
   Span<SocketDeclarationPtr> sockets(eNodeSocketInOut in_out) const;
 
+  const aal::RelationsInNode *anonymous_attribute_relations() const
+  {
+    return anonymous_attribute_relations_.get();
+  }
+
   MEM_CXX_CLASS_ALLOC_FUNCS("NodeDeclaration")
 };
 
 class NodeDeclarationBuilder {
  private:
   NodeDeclaration &declaration_;
-  Vector<std::unique_ptr<BaseSocketDeclarationBuilder>> builders_;
+  Vector<std::unique_ptr<BaseSocketDeclarationBuilder>> input_builders_;
+  Vector<std::unique_ptr<BaseSocketDeclarationBuilder>> output_builders_;
   bool is_function_node_ = false;
 
  public:
@@ -333,6 +500,14 @@ class NodeDeclarationBuilder {
   template<typename DeclType>
   typename DeclType::Builder &add_output(StringRef name, StringRef identifier = "");
 
+  aal::RelationsInNode &get_anonymous_attribute_relations()
+  {
+    if (!declaration_.anonymous_attribute_relations_) {
+      declaration_.anonymous_attribute_relations_ = std::make_unique<aal::RelationsInNode>();
+    }
+    return *declaration_.anonymous_attribute_relations_;
+  }
+
  private:
   template<typename DeclType>
   typename DeclType::Builder &add_socket(StringRef name,
@@ -349,6 +524,44 @@ void id_or_index(const bNode &node, void *r_value);
 
 void build_node_declaration(const bNodeType &typeinfo, NodeDeclaration &r_declaration);
 
+template<typename SocketDecl>
+typename SocketDeclarationBuilder<SocketDecl>::Self &SocketDeclarationBuilder<
+    SocketDecl>::reference_pass(const Span<int> input_indices)
+{
+  aal::RelationsInNode &relations = node_decl_builder_->get_anonymous_attribute_relations();
+  for (const int from_input : input_indices) {
+    aal::ReferenceRelation relation;
+    relation.from_field_input = from_input;
+    relation.to_field_output = index_;
+    relations.reference_relations.append(relation);
+  }
+  return *(Self *)this;
+}
+
+template<typename SocketDecl>
+typename SocketDeclarationBuilder<SocketDecl>::Self &SocketDeclarationBuilder<
+    SocketDecl>::field_on(const Span<int> indices)
+{
+  aal::RelationsInNode &relations = node_decl_builder_->get_anonymous_attribute_relations();
+  if (decl_->in_out == SOCK_IN) {
+    for (const int input_index : indices) {
+      aal::EvalRelation relation;
+      relation.field_input = index_;
+      relation.geometry_input = input_index;
+      relations.eval_relations.append(relation);
+    }
+  }
+  else {
+    for (const int output_index : indices) {
+      aal::AvailableRelation relation;
+      relation.field_output = index_;
+      relation.geometry_output = output_index;
+      relations.available_relations.append(relation);
+    }
+  }
+  return *(Self *)this;
+}
+
 /* -------------------------------------------------------------------- */
 /** \name #OutputFieldDependency Inline Methods
  * \{ */
@@ -490,12 +703,15 @@ inline typename DeclType::Builder &NodeDeclarationBuilder::add_socket(StringRef
   std::unique_ptr<DeclType> socket_decl = std::make_unique<DeclType>();
   std::unique_ptr<Builder> socket_decl_builder = std::make_unique<Builder>();
   socket_decl_builder->decl_ = &*socket_decl;
+
+  socket_decl_builder->node_decl_builder_ = this;
   socket_decl->name = name;
   socket_decl->identifier = identifier.is_empty() ? name : identifier;
   socket_decl->in_out 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list