[Bf-blender-cvs] [617954c1438] master: Geometry Nodes: new Instance on Points node

Jacques Lucke noreply at git.blender.org
Mon Sep 27 10:17:28 CEST 2021


Commit: 617954c1438096810ce8e47f09c25c8311baac4d
Author: Jacques Lucke
Date:   Mon Sep 27 10:16:38 2021 +0200
Branches: master
https://developer.blender.org/rB617954c1438096810ce8e47f09c25c8311baac4d

Geometry Nodes: new Instance on Points node

This adds a new Instance on Points node that is a replacement
for the old Point Instance node. Contrary to the old node,
it does not have a mode to instance objects or collections
directly. Instead, the node has to be used with an Object/
Collection Info to achieve the same effect.

Rotation and scale of the instances can be adjusted in the node
directly or can be controlled with a field to get some variation
between instances.

The node supports placing different instances on different points.
The user has control over which instance is placed on which point
using an Instance Index input. If that functionality is used, the
Instance Geometry has to contain multiple instances that can are
instanced separately.

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

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

M	release/scripts/startup/nodeitems_builtins.py
M	source/blender/blenkernel/BKE_geometry_set.hh
M	source/blender/blenkernel/BKE_node.h
M	source/blender/blenkernel/intern/geometry_component_instances.cc
M	source/blender/blenkernel/intern/geometry_set.cc
M	source/blender/blenkernel/intern/node.cc
M	source/blender/modifiers/intern/MOD_nodes_evaluator.cc
M	source/blender/nodes/CMakeLists.txt
M	source/blender/nodes/NOD_geometry.h
M	source/blender/nodes/NOD_geometry_exec.hh
M	source/blender/nodes/NOD_static_types.h
R100	source/blender/nodes/geometry/nodes/node_geo_point_instance.cc	source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc
A	source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc

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

diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index e658706a946..88a0782a102 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -593,6 +593,7 @@ geometry_node_categories = [
         NodeItem("GeometryNodeMeshUVSphere"),
     ]),
     GeometryNodeCategory("GEO_POINT", "Point", items=[
+        NodeItem("GeometryNodeInstanceOnPoints", poll=geometry_nodes_fields_poll),
         NodeItem("GeometryNodeDistributePointsOnFaces", poll=geometry_nodes_fields_poll),
         NodeItem("GeometryNodeLegacyPointDistribute", poll=geometry_nodes_fields_legacy_poll),
         NodeItem("GeometryNodeLegacyPointInstance", poll=geometry_nodes_fields_legacy_poll),
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 5fcdbc83e25..571c6c6a0a0 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -323,6 +323,7 @@ struct GeometrySet {
   bool has_instances() const;
   bool has_volume() const;
   bool has_curve() const;
+  bool has_realized_data() const;
 
   const Mesh *get_mesh_for_read() const;
   const PointCloud *get_pointcloud_for_read() const;
@@ -478,7 +479,7 @@ class InstanceReference {
   Type type_ = Type::None;
   /** Depending on the type this is either null, an Object or Collection pointer. */
   void *data_ = nullptr;
-  std::unique_ptr<GeometrySet> geometry_set_;
+  std::shared_ptr<GeometrySet> geometry_set_;
 
  public:
   InstanceReference() = default;
@@ -493,17 +494,10 @@ class InstanceReference {
 
   InstanceReference(GeometrySet geometry_set)
       : type_(Type::GeometrySet),
-        geometry_set_(std::make_unique<GeometrySet>(std::move(geometry_set)))
+        geometry_set_(std::make_shared<GeometrySet>(std::move(geometry_set)))
   {
   }
 
-  InstanceReference(const InstanceReference &src) : type_(src.type_), data_(src.data_)
-  {
-    if (src.type_ == Type::GeometrySet) {
-      geometry_set_ = std::make_unique<GeometrySet>(*src.geometry_set_);
-    }
-  }
-
   Type type() const
   {
     return type_;
@@ -595,6 +589,7 @@ class InstancesComponent : public GeometryComponent {
   void add_instance(int instance_handle, const blender::float4x4 &transform, const int id = -1);
 
   blender::Span<InstanceReference> references() const;
+  void remove_unused_references();
 
   void ensure_geometry_instances();
   GeometrySet &geometry_set_from_reference(const int reference_index);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 52f8a3d8136..5491f2a3de9 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1502,6 +1502,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
 #define GEO_NODE_CURVE_FILLET 1089
 #define GEO_NODE_DISTRIBUTE_POINTS_ON_FACES 1090
 #define GEO_NODE_STRING_TO_CURVES 1091
+#define GEO_NODE_INSTANCE_ON_POINTS 1092
 
 /** \} */
 
diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc
index 9479d012cb8..f1f60266545 100644
--- a/source/blender/blenkernel/intern/geometry_component_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_component_instances.cc
@@ -14,11 +14,14 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
+#include <mutex>
+
 #include "BLI_float4x4.hh"
 #include "BLI_map.hh"
 #include "BLI_rand.hh"
 #include "BLI_set.hh"
 #include "BLI_span.hh"
+#include "BLI_task.hh"
 #include "BLI_vector.hh"
 
 #include "DNA_collection_types.h"
@@ -182,6 +185,86 @@ blender::Span<InstanceReference> InstancesComponent::references() const
   return references_;
 }
 
+void InstancesComponent::remove_unused_references()
+{
+  using namespace blender;
+  using namespace blender::bke;
+
+  const int tot_instances = this->instances_amount();
+  const int tot_references_before = references_.size();
+
+  if (tot_instances == 0) {
+    /* If there are no instances, no reference is needed. */
+    references_.clear();
+    return;
+  }
+  if (tot_references_before == 1) {
+    /* There is only one reference and at least one instance. So the only existing reference is
+     * used. Nothing to do here. */
+    return;
+  }
+
+  Array<bool> usage_by_handle(tot_references_before, false);
+  std::mutex mutex;
+
+  /* Loop over all instances to see which references are used. */
+  threading::parallel_for(IndexRange(tot_instances), 1000, [&](IndexRange range) {
+    /* Use local counter to avoid lock contention. */
+    Array<bool> local_usage_by_handle(tot_references_before, false);
+
+    for (const int i : range) {
+      const int handle = instance_reference_handles_[i];
+      BLI_assert(handle >= 0 && handle < tot_references_before);
+      local_usage_by_handle[handle] = true;
+    }
+
+    std::lock_guard lock{mutex};
+    for (const int i : IndexRange(tot_references_before)) {
+      usage_by_handle[i] |= local_usage_by_handle[i];
+    }
+  });
+
+  if (!usage_by_handle.as_span().contains(false)) {
+    /* All references are used. */
+    return;
+  }
+
+  /* Create new references and a mapping for the handles. */
+  Vector<int> handle_mapping;
+  VectorSet<InstanceReference> new_references;
+  int next_new_handle = 0;
+  bool handles_have_to_be_updated = false;
+  for (const int old_handle : IndexRange(tot_references_before)) {
+    if (!usage_by_handle[old_handle]) {
+      /* Add some dummy value. It won't be read again. */
+      handle_mapping.append(-1);
+    }
+    else {
+      const InstanceReference &reference = references_[old_handle];
+      handle_mapping.append(next_new_handle);
+      new_references.add_new(reference);
+      if (old_handle != next_new_handle) {
+        handles_have_to_be_updated = true;
+      }
+      next_new_handle++;
+    }
+  }
+  references_ = new_references;
+
+  if (!handles_have_to_be_updated) {
+    /* All remaining handles are the same as before, so they don't have to be updated. This happens
+     * when unused handles are only at the end. */
+    return;
+  }
+
+  /* Update handles of instances. */
+  threading::parallel_for(IndexRange(tot_instances), 1000, [&](IndexRange range) {
+    for (const int i : range) {
+      instance_reference_handles_[i] = handle_mapping[instance_reference_handles_[i]];
+    }
+  });
+}
+
 int InstancesComponent::instances_amount() const
 {
   return instance_transforms_.size();
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 54e9fadf8ed..1ebdde75f46 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -291,6 +291,19 @@ bool GeometrySet::has_curve() const
   return component != nullptr && component->has_curve();
 }
 
+/* Returns true when the geometry set has any data that is not an instance. */
+bool GeometrySet::has_realized_data() const
+{
+  if (components_.is_empty()) {
+    return false;
+  }
+  if (components_.size() > 1) {
+    return true;
+  }
+  /* Check if the only component is an #InstancesComponent. */
+  return this->get_component_for_read<InstancesComponent>() == nullptr;
+}
+
 /* Create a new geometry set that only contains the given mesh. */
 GeometrySet GeometrySet::create_with_mesh(Mesh *mesh, GeometryOwnershipType ownership)
 {
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index c10aa3bbc5a..f1f643ffed7 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -5764,6 +5764,7 @@ static void registerGeometryNodes()
   register_node_type_geo_delete_geometry();
   register_node_type_geo_distribute_points_on_faces();
   register_node_type_geo_edge_split();
+  register_node_type_geo_instance_on_points();
   register_node_type_geo_input_index();
   register_node_type_geo_input_material();
   register_node_type_geo_input_normal();
diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
index fd0205cffc5..6f18c4d40db 100644
--- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
+++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
@@ -328,17 +328,21 @@ static void get_socket_value(const SocketRef &socket, void *r_value)
    * more complex defaults (other than just single values) in their socket declarations. */
   if (bsocket.flag & SOCK_HIDE_VALUE) {
     const bNode &bnode = *socket.bnode();
-    if (bsocket.type == SOCK_VECTOR &&
-        ELEM(bnode.type, GEO_NODE_SET_POSITION, SH_NODE_TEX_NOISE)) {
-      new (r_value) Field<float3>(
-          std::make_shared<bke::AttributeFieldInput>("position", CPPType::get<float3>()));
-      return;
+    if (bsocket.type == SOCK_VECTOR) {
+      if (ELEM(bnode.type, GEO_NODE_SET_POSITION, SH_NODE_TEX_NOISE)) {
+        new (r_value) Field<float3>(
+            std::make_shared<bke::AttributeFieldInput>("position", CPPType::get<float3>()));
+        return;
+      }
     }
-    if (bsocket.type == SOCK_INT && bnode.type == FN_NODE_RANDOM_VALUE) {
-      new (r_value) Field<int>(std::make_shared<fn::IndexFieldInput>());
-      return;
+    else if (bsocket.type == SOCK_INT) {
+      if (ELEM(bnode.type, FN_NODE_RANDOM_VALUE, GEO_NODE_INSTANCE_ON_POINTS)) {
+        new (r_value) Field<int>(std::make_shared<fn::IndexFieldInput>());
+        return;
+      }
     }
   }
+
   const bNodeSocketType *typeinfo = socket.typeinfo();
   typeinfo->get_geometry_nodes_cpp_value(*socket.bsocket(), r_value);
 }
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index e1cceae2964..844e838272c 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -151,6 +151,7 @@ set(SRC
   geometry/nodes/legacy/node_geo_material_assign.cc
   geometry/nodes/legacy/node_geo_select_by_material.cc
   geometry/nodes/legacy/node_geo_point_distribute.cc
+  geometry/nodes/legacy/node_geo_point_instance.cc
 
   geometry/nodes/node_geo_align_rotation_to_vector.cc
   geometry/nodes/node_geo_attribute_capture.cc
@@ -202,

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list