[Bf-blender-cvs] [0feca5f07da] geometry-nodes: Geometry Nodes: initial object socket support

Jacques Lucke noreply at git.blender.org
Thu Nov 12 13:30:53 CET 2020


Commit: 0feca5f07da1d04b3c4bd72c96090389aab6f301
Author: Jacques Lucke
Date:   Thu Nov 12 12:20:59 2020 +0100
Branches: geometry-nodes
https://developer.blender.org/rB0feca5f07da1d04b3c4bd72c96090389aab6f301

Geometry Nodes: initial object socket support

The fundamental difference between object sockets and the
other existing data sockets is that an object is an ID data block.
Changing the value of an object socket also changes the depsgraph.

The modifier has to analyse the node tree to figure out which other
objects it depends on. Currently, this is done very simply by just
looping over all sockets and collecting the objects. In the future
this can be improved by also figuring out what components of
an object are needed.

Instead of passing object pointers around in the node tree, we actually
use a handle. This handle is just a number internally that identifies
a specific object. The conversion between handles and object pointers
is done using a map that is provided by the modifier.

This approach has a couple of benefits. It protects us a bit from passing
around pointers that are not known to the modifier and therefore are
not in the depsgraph. Furthermore, the object pointer can change
while the handle stays the same. This is not important right now, but
is not unlikely to become useful in the future.

The API for how nodes access object pointers is not ideal yet and
will be improved in the future.

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

M	source/blender/makesrna/intern/rna_nodetree.c
M	source/blender/modifiers/intern/MOD_nodes.cc
M	source/blender/nodes/NOD_geometry_exec.hh

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

diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 82c55c85d13..35e29722c0a 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -2857,6 +2857,7 @@ static void rna_NodeSocketStandard_value_and_relation_update(struct bContext *C,
   bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
   Main *bmain = CTX_data_main(C);
   ntreeUpdateTree(bmain, ntree);
+  DEG_relations_tag_update(bmain);
 }
 
 /* ******** Node Types ******** */
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index c3645f38481..082067d365b 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -29,6 +29,7 @@
 
 #include "BLI_float3.hh"
 #include "BLI_listbase.h"
+#include "BLI_set.hh"
 #include "BLI_string.h"
 #include "BLI_utildefines.h"
 
@@ -74,6 +75,12 @@
 
 using blender::float3;
 
+/* To be replaced soon. */
+using namespace blender;
+using namespace blender::nodes;
+using namespace blender::fn;
+using namespace blender::bke;
+
 static void initData(ModifierData *md)
 {
   NodesModifierData *nmd = (NodesModifierData *)md;
@@ -83,11 +90,49 @@ static void initData(ModifierData *md)
   MEMCPY_STRUCT_AFTER(nmd, DNA_struct_default_get(NodesModifierData), modifier);
 }
 
+static void addIdsUsedBySocket(const ListBase *sockets, Set<ID *> &ids)
+{
+  LISTBASE_FOREACH (const bNodeSocket *, socket, sockets) {
+    if (socket->type == SOCK_OBJECT) {
+      Object *object = ((bNodeSocketValueObject *)socket->default_value)->value;
+      if (object != nullptr) {
+        ids.add(&object->id);
+      }
+    }
+  }
+}
+
+static void findUsedIds(const bNodeTree &tree, Set<ID *> &ids)
+{
+  Set<const bNodeTree *> handled_groups;
+
+  LISTBASE_FOREACH (const bNode *, node, &tree.nodes) {
+    addIdsUsedBySocket(&node->inputs, ids);
+    addIdsUsedBySocket(&node->outputs, ids);
+
+    if (node->type == NODE_GROUP) {
+      const bNodeTree *group = (bNodeTree *)node->id;
+      if (group != nullptr && handled_groups.add(group)) {
+        findUsedIds(*group, ids);
+      }
+    }
+  }
+}
+
 static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
 {
   NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
   if (nmd->node_group != nullptr) {
     DEG_add_node_tree_relation(ctx->node, nmd->node_group, "Nodes Modifier");
+
+    Set<ID *> used_ids;
+    findUsedIds(*nmd->node_group, used_ids);
+    for (ID *id : used_ids) {
+      if (GS(id->name) == ID_OB) {
+        DEG_add_object_relation(ctx->node, (Object *)id, DEG_OB_COMP_TRANSFORM, "Nodes Modifier");
+        DEG_add_object_relation(ctx->node, (Object *)id, DEG_OB_COMP_GEOMETRY, "Nodes Modifier");
+      }
+    }
   }
 
   /* TODO: Add relations for IDs in settings. */
@@ -147,14 +192,17 @@ class GeometryNodesEvaluator {
   Vector<const DInputSocket *> group_outputs_;
   MultiFunctionByNode &mf_by_node_;
   const DataTypeConversions &conversions_;
+  const PersistentDataHandleMap &handle_map_;
 
  public:
   GeometryNodesEvaluator(const Map<const DOutputSocket *, GMutablePointer> &group_input_data,
                          Vector<const DInputSocket *> group_outputs,
-                         MultiFunctionByNode &mf_by_node)
+                         MultiFunctionByNode &mf_by_node,
+                         const PersistentDataHandleMap &handle_map)
       : group_outputs_(std::move(group_outputs)),
         mf_by_node_(mf_by_node),
-        conversions_(get_implicit_type_conversions())
+        conversions_(get_implicit_type_conversions()),
+        handle_map_(handle_map)
   {
     for (auto item : group_input_data.items()) {
       this->forward_to_inputs(*item.key, item.value);
@@ -188,21 +236,13 @@ class GeometryNodesEvaluator {
     const int total_inputs = from_sockets.size() + from_group_inputs.size();
     BLI_assert(total_inputs <= 1);
 
-    const CPPType &type = *socket_cpp_type_get(*socket_to_compute.typeinfo());
-
     if (total_inputs == 0) {
       /* The input is not connected, use the value from the socket itself. */
-      bNodeSocket &bsocket = *socket_to_compute.bsocket();
-      void *buffer = allocator_.allocate(type.size(), type.alignment());
-      socket_cpp_value_get(bsocket, buffer);
-      return GMutablePointer{type, buffer};
+      return get_unlinked_input_value(socket_to_compute);
     }
     if (from_group_inputs.size() == 1) {
       /* The input gets its value from the input of a group that is not further connected. */
-      bNodeSocket &bsocket = *from_group_inputs[0]->bsocket();
-      void *buffer = allocator_.allocate(type.size(), type.alignment());
-      socket_cpp_value_get(bsocket, buffer);
-      return GMutablePointer{type, buffer};
+      return get_unlinked_input_value(socket_to_compute);
     }
 
     /* Compute the socket now. */
@@ -227,7 +267,7 @@ class GeometryNodesEvaluator {
 
     /* Execute the node. */
     GValueMap<StringRef> node_outputs_map{allocator_};
-    GeoNodeInputs node_inputs{bnode, node_inputs_map};
+    GeoNodeInputs node_inputs{bnode, node_inputs_map, handle_map_};
     GeoNodeOutputs node_outputs{bnode, node_outputs_map};
     this->execute_node(node, node_inputs, node_outputs);
 
@@ -329,6 +369,30 @@ class GeometryNodesEvaluator {
       }
     }
   }
+
+  GMutablePointer get_unlinked_input_value(const DInputSocket &socket)
+  {
+    bNodeSocket *bsocket;
+    if (socket.linked_group_inputs().size() == 0) {
+      bsocket = socket.bsocket();
+    }
+    else {
+      bsocket = socket.linked_group_inputs()[0]->bsocket();
+    }
+    const CPPType &type = *socket_cpp_type_get(*socket.typeinfo());
+    void *buffer = allocator_.allocate(type.size(), type.alignment());
+
+    if (bsocket->type == SOCK_OBJECT) {
+      Object *object = ((bNodeSocketValueObject *)bsocket->default_value)->value;
+      PersistentObjectHandle object_handle = handle_map_.lookup(object);
+      new (buffer) PersistentObjectHandle(object_handle);
+    }
+    else {
+      socket_cpp_value_get(*bsocket, buffer);
+    }
+
+    return {type, buffer};
+  }
 };
 
 /**
@@ -649,6 +713,18 @@ static void initialize_group_input(NodesModifierData &nmd,
   property_type->init_cpp_value(*property, r_value);
 }
 
+static void fill_data_handle_map(const DerivedNodeTree &tree, PersistentDataHandleMap &handle_map)
+{
+  Set<ID *> used_ids;
+  findUsedIds(*tree.btree(), used_ids);
+
+  int current_handle = 0;
+  for (ID *id : used_ids) {
+    handle_map.add(current_handle, *id);
+    current_handle++;
+  }
+}
+
 /**
  * Evaluate a node group to compute the output geometry.
  * Currently, this uses a fairly basic and inefficient algorithm that might compute things more
@@ -691,7 +767,10 @@ static GeometrySetPtr compute_geometry(const DerivedNodeTree &tree,
   Vector<const DInputSocket *> group_outputs;
   group_outputs.append(&socket_to_compute);
 
-  GeometryNodesEvaluator evaluator{group_inputs, group_outputs, mf_by_node};
+  PersistentDataHandleMap handle_map;
+  fill_data_handle_map(tree, handle_map);
+
+  GeometryNodesEvaluator evaluator{group_inputs, group_outputs, mf_by_node, handle_map};
   Vector<GMutablePointer> results = evaluator.execute();
   BLI_assert(results.size() == 1);
   GMutablePointer result = results[0];
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index ff2aa037f06..db28cdbd844 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -19,15 +19,20 @@
 #include "FN_generic_value_map.hh"
 
 #include "BKE_geometry_set.hh"
+#include "BKE_persistent_data_handle.hh"
 
 #include "DNA_node_types.h"
 
 namespace blender::nodes {
 
+using bke::GeometryOwnershipType;
 using bke::GeometrySet;
 using bke::GeometrySetPtr;
+using bke::InstancesComponent;
 using bke::make_geometry_set_mutable;
 using bke::MeshComponent;
+using bke::PersistentDataHandleMap;
+using bke::PersistentObjectHandle;
 using bke::PointCloudComponent;
 using fn::CPPType;
 using fn::GMutablePointer;
@@ -37,12 +42,21 @@ class GeoNodeInputs {
  private:
   const bNode *node_;
   GValueMap<StringRef> &values_;
+  const PersistentDataHandleMap &handle_map_;
 
  public:
-  GeoNodeInputs(const bNode &node, GValueMap<StringRef> &values) : node_(&node), values_(values)
+  GeoNodeInputs(const bNode &node,
+                GValueMap<StringRef> &values,
+                const PersistentDataHandleMap &handle_map)
+      : node_(&node), values_(values), handle_map_(handle_map)
   {
   }
 
+  const PersistentDataHandleMap &handle_map() const
+  {
+    return handle_map_;
+  }
+
   /**
    * Get the input value for the input socket with the given identifier.
    *



More information about the Bf-blender-cvs mailing list