[Bf-blender-cvs] [61f3d4eb7c7] master: Geometry Nodes: Initial socket visualization for fields.

Jacques Lucke noreply at git.blender.org
Thu Sep 23 22:22:36 CEST 2021


Commit: 61f3d4eb7c7db711f9339d05e68b8f9eac3ce167
Author: Jacques Lucke
Date:   Thu Sep 23 15:21:31 2021 -0500
Branches: master
https://developer.blender.org/rB61f3d4eb7c7db711f9339d05e68b8f9eac3ce167

Geometry Nodes: Initial socket visualization for fields.

This implements the update logic for the vizualization of which
sockets pass data or constants directly, and which pass functions.
The socket shapes may still have to be updated. That should be
done separately, because it might be a bit more involved, because
socket shapes are currently linked to keyframe shapes. Currently
the circle and diamond shapes are used with the following meanings:

 - Input Sockets:
    - Circle: Required to be a single value.
    - Diamond: This input supports fields.
 - Output Sockets:
    - Circle: This output is a single value.
    - Diamond: This output may be a field.

Connecting a field to a circle input socket is an error, since a
field cannot be converted to a single value. If the socket shape
is a diamond with a dot in the middle, it means it is currently
a single value, but could be a field.

In addition to socket shapes, the intention is to draw node links
differently based on the field status. However, the exact method for
conveying that isn't decided yet.

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

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

M	source/blender/blenkernel/BKE_node.h
M	source/blender/blenkernel/intern/lib_remap.c
M	source/blender/blenkernel/intern/node.cc
M	source/blender/editors/space_node/drawnode.cc
M	source/blender/editors/space_node/node_relationships.cc
M	source/blender/makesdna/DNA_node_types.h
M	source/blender/nodes/NOD_node_declaration.hh
M	source/blender/nodes/NOD_node_tree_ref.hh
M	source/blender/nodes/function/nodes/node_fn_boolean_math.cc
M	source/blender/nodes/function/nodes/node_fn_float_compare.cc
M	source/blender/nodes/function/nodes/node_fn_float_to_int.cc
M	source/blender/nodes/function/nodes/node_fn_input_string.cc
M	source/blender/nodes/function/nodes/node_fn_input_vector.cc
M	source/blender/nodes/function/nodes/node_fn_random_float.cc
M	source/blender/nodes/function/nodes/node_fn_string_length.cc
M	source/blender/nodes/function/nodes/node_fn_string_substring.cc
M	source/blender/nodes/function/nodes/node_fn_value_to_string.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_curve_parameter.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
M	source/blender/nodes/geometry/nodes/node_geo_input_index.cc
M	source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
M	source/blender/nodes/geometry/nodes/node_geo_input_position.cc
M	source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
M	source/blender/nodes/geometry/nodes/node_geo_material_assign.cc
M	source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
M	source/blender/nodes/geometry/nodes/node_geo_set_position.cc
M	source/blender/nodes/intern/node_tree_ref.cc
M	source/blender/nodes/shader/nodes/node_shader_clamp.cc
M	source/blender/nodes/shader/nodes/node_shader_curves.cc
M	source/blender/nodes/shader/nodes/node_shader_map_range.cc
M	source/blender/nodes/shader/nodes/node_shader_math.cc
M	source/blender/nodes/shader/nodes/node_shader_mixRgb.cc
M	source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc
M	source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc
M	source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
M	source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
M	source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
M	source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
M	source/blender/nodes/shader/nodes/node_shader_valToRgb.cc
M	source/blender/nodes/shader/nodes/node_shader_vector_math.cc
M	source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc

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

diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 21ca65baf00..2e843e82a9f 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -480,7 +480,7 @@ bool ntreeHasType(const struct bNodeTree *ntree, int type);
 bool ntreeHasTree(const struct bNodeTree *ntree, const struct bNodeTree *lookup);
 void ntreeUpdateTree(struct Main *main, struct bNodeTree *ntree);
 void ntreeUpdateAllNew(struct Main *main);
-void ntreeUpdateAllUsers(struct Main *main, struct ID *id);
+void ntreeUpdateAllUsers(struct Main *main, struct ID *id, int tree_update_flag);
 
 void ntreeGetDependencyList(struct bNodeTree *ntree,
                             struct bNode ***r_deplist,
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index 250b8d4d515..48396c5e6d9 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -345,7 +345,7 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *o
 static void libblock_remap_data_postprocess_nodetree_update(Main *bmain, ID *new_id)
 {
   /* Update all group nodes using a node group. */
-  ntreeUpdateAllUsers(bmain, new_id);
+  ntreeUpdateAllUsers(bmain, new_id, 0);
 }
 
 /**
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index d56a7bf8fb4..f223ed28301 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -52,9 +52,12 @@
 #include "BLI_map.hh"
 #include "BLI_math.h"
 #include "BLI_path_util.h"
+#include "BLI_set.hh"
+#include "BLI_stack.hh"
 #include "BLI_string.h"
 #include "BLI_string_utils.h"
 #include "BLI_utildefines.h"
+#include "BLI_vector_set.hh"
 
 #include "BLT_translation.h"
 
@@ -80,6 +83,7 @@
 #include "NOD_function.h"
 #include "NOD_geometry.h"
 #include "NOD_node_declaration.hh"
+#include "NOD_node_tree_ref.hh"
 #include "NOD_shader.h"
 #include "NOD_socket.h"
 #include "NOD_texture.h"
@@ -93,6 +97,20 @@
 
 #define NODE_DEFAULT_MAX_WIDTH 700
 
+using blender::Array;
+using blender::MutableSpan;
+using blender::Set;
+using blender::Span;
+using blender::Stack;
+using blender::Vector;
+using blender::VectorSet;
+using blender::nodes::InputSocketFieldType;
+using blender::nodes::NodeDeclaration;
+using blender::nodes::OutputFieldDependency;
+using blender::nodes::OutputSocketFieldType;
+using blender::nodes::SocketDeclaration;
+using namespace blender::nodes::node_tree_ref_types;
+
 /* Fallback types for undefined tree, nodes, sockets */
 static bNodeTreeType NodeTreeTypeUndefined;
 bNodeType NodeTypeUndefined;
@@ -110,6 +128,10 @@ static void node_socket_interface_free(bNodeTree *UNUSED(ntree),
 static void nodeMuteRerouteOutputLinks(struct bNodeTree *ntree,
                                        struct bNode *node,
                                        const bool mute);
+static FieldInferencingInterface *node_field_inferencing_interface_copy(
+    const FieldInferencingInterface &field_inferencing_interface);
+static void node_field_inferencing_interface_free(
+    const FieldInferencingInterface *field_inferencing_interface);
 
 static void ntree_init_data(ID *id)
 {
@@ -220,6 +242,11 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
 
   /* node tree will generate its own interface type */
   ntree_dst->interface_type = nullptr;
+
+  if (ntree_src->field_inferencing_interface) {
+    ntree_dst->field_inferencing_interface = node_field_inferencing_interface_copy(
+        *ntree_src->field_inferencing_interface);
+  }
 }
 
 static void ntree_free_data(ID *id)
@@ -265,6 +292,8 @@ static void ntree_free_data(ID *id)
     MEM_freeN(sock);
   }
 
+  node_field_inferencing_interface_free(ntree->field_inferencing_interface);
+
   /* free preview hash */
   if (ntree->previews) {
     BKE_node_instance_hash_free(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free);
@@ -647,6 +676,8 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
   ntree->progress = nullptr;
   ntree->execdata = nullptr;
 
+  ntree->field_inferencing_interface = nullptr;
+
   BLO_read_data_address(reader, &ntree->adt);
   BKE_animdata_blend_read_data(reader, ntree->adt);
 
@@ -4425,7 +4456,518 @@ void ntreeUpdateAllNew(Main *main)
   FOREACH_NODETREE_END;
 }
 
-void ntreeUpdateAllUsers(Main *main, ID *id)
+/**
+ * Information about how a node interacts with fields.
+ */
+struct FieldInferencingInterface {
+  Vector<InputSocketFieldType> inputs;
+  Vector<OutputFieldDependency> outputs;
+
+  friend bool operator==(const FieldInferencingInterface &a, const FieldInferencingInterface &b)
+  {
+    return a.inputs == b.inputs && a.outputs == b.outputs;
+  }
+
+  friend bool operator!=(const FieldInferencingInterface &a, const FieldInferencingInterface &b)
+  {
+    return !(a == b);
+  }
+};
+
+static FieldInferencingInterface *node_field_inferencing_interface_copy(
+    const FieldInferencingInterface &field_inferencing_interface)
+{
+  return new FieldInferencingInterface(field_inferencing_interface);
+}
+
+static void node_field_inferencing_interface_free(
+    const FieldInferencingInterface *field_inferencing_interface)
+{
+  delete field_inferencing_interface;
+}
+
+namespace blender::bke::node_field_inferencing {
+
+static bool is_field_socket_type(eNodeSocketDatatype type)
+{
+  return ELEM(type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA);
+}
+
+static bool is_field_socket_type(const SocketRef &socket)
+{
+  return is_field_socket_type((eNodeSocketDatatype)socket.typeinfo()->type);
+}
+
+static bool update_field_inferencing(bNodeTree &btree);
+
+static InputSocketFieldType get_interface_input_field_type(const NodeRef &node,
+                                                           const InputSocketRef &socket)
+{
+  if (!is_field_socket_type(socket)) {
+    return InputSocketFieldType::None;
+  }
+  if (node.is_reroute_node()) {
+    return InputSocketFieldType::IsSupported;
+  }
+  if (node.is_group_output_node()) {
+    /* Outputs always support fields when the data type is correct. */
+    return InputSocketFieldType::IsSupported;
+  }
+
+  const NodeDeclaration *node_decl = node.declaration();
+
+  /* Node declarations should be implemented for nodes involved here. */
+  BLI_assert(node_decl != nullptr);
+
+  if (node_decl->is_function_node()) {
+    /* In a function node, every socket supports fields. */
+    return InputSocketFieldType::IsSupported;
+  }
+  /* Get the field type from the declaration. */
+  const SocketDeclaration &socket_decl = *node_decl->inputs()[socket.index()];
+  return socket_decl.input_field_type();
+}
+
+static OutputFieldDependency get_interface_output_field_dependency(const NodeRef &node,
+                                                                   const OutputSocketRef &socket)
+{
+  if (!is_field_socket_type(socket)) {
+    /* Non-field sockets always output data. */
+    return OutputFieldDependency::ForDataSource();
+  }
+  if (node.is_reroute_node()) {
+    /* The reroute just forwards what is passed in. */
+    return OutputFieldDependency::ForDependentField();
+  }
+  if (node.is_group_input_node()) {
+    /* Input nodes get special treatment in #determine_group_input_states. */
+    return OutputFieldDependency::ForDependentField();
+  }
+
+  const NodeDeclaration *node_decl = node.declaration();
+
+  /* Node declarations should be implemented for nodes involved here. */
+  BLI_assert(node_decl != nullptr);
+
+  if (node_decl->is_function_node()) {
+    /* In a generic function node, all outputs depend on all inputs. */
+    return OutputFieldDependency::ForDependentField();
+  }
+
+  /* Use the socket declaration. */
+  const SocketDeclaration &socket_decl = *node_decl->outputs()[socket.index()];
+  return socket_decl.output_field_dependency();
+}
+
+/**
+ * Retrieves information about how the node interacts with fields.
+ * In the future, this information can be stored in the node declaration. This would allow this
+ * function to return a reference, making it more efficient.
+ */
+static FieldInferencingInterface get_node_field_inferencing_interface(const NodeRef &node)
+{
+  /* Node groups already reference all required information, so just return that. */
+  if (node.is_group_node()) {
+    bNodeTree *group = (bNodeTree *)node.bnode()->id;
+    if (group == nullptr) {
+      return FieldInferencingInterface();
+    }
+    if (group->field_inferencing_interface == nullptr) {
+      /* Update group recursively. */
+      update_field_inferencing(*group);
+    }
+    return *group->field_inferencing_interface;
+  }
+
+  FieldInferencingInterface inferencing_interface;
+  for (const InputSocketRef *input_socket : node.inputs()) {
+    inferencing_interface.inputs.append(get_interface_input_field_type(node, *input_socket));
+  }
+
+  for (const OutputSocketRef *output_socket : node.outputs()) {
+    inferencing_interface.outputs.append(
+        get_interface_output_field_dependency(node, *output_socket));
+  }
+  return inferencing_interface;
+}
+
+/**
+ * This struct contains information for every socket. The values are propagated through the
+ * network.
+ */
+struct SocketFieldState {
+  /* This socket is currently a single value. It could become a field though. */
+  bool is_single = true;
+  /* This socket is required to be a single value. It must not be a field. */
+  bool requires_single = false;
+  /* This socket starts a new field. */
+  bool is_field_source = false;
+};
+
+static Vector<const InputSocketRef *> gather_input_socket_dependencies(
+    const OutputFieldDependency &field_dependency, const NodeRef &node)
+{
+  const OutputSocketFieldType type = field_dependency.field_type();
+  Vector<const InputSocketRef *> input_sockets;
+  switch (type) {
+    case OutputSocketFieldType::FieldSource:
+    case OutputSocketFieldType::None: {
+      break;
+    }
+    case OutputSocketFieldType::DependentField: {
+      /* This output depends on all inputs. */
+      input_sockets.extend(node.inputs());
+      break;
+    }
+    case OutputSocketFieldType::PartiallyDependent: {
+      /* This output depends

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list