[Bf-blender-cvs] [6d162d35e2c] master: Geometry Nodes: Fill instances separately in the curve fill node

Hans Goudey noreply at git.blender.org
Tue Sep 21 21:21:12 CEST 2021


Commit: 6d162d35e2c85ea4fb990f0c459ec36064cf0550
Author: Hans Goudey
Date:   Tue Sep 21 14:20:54 2021 -0500
Branches: master
https://developer.blender.org/rB6d162d35e2c85ea4fb990f0c459ec36064cf0550

Geometry Nodes: Fill instances separately in the curve fill node

With this commit, each referenced instance data will be converted to
a geometry instances and processed separately. This should result in
a large speedup when the instances component has many insances
referring to the same data.

This change can act as a blueprint for other nodes that need to
implement similar behavior. It adds some helper functions on the
instances component to make that easier.

Thanks to Erik Abrahamsson for a proof of concept patch.

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

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

M	source/blender/blenkernel/BKE_geometry_set.hh
M	source/blender/blenkernel/intern/geometry_component_instances.cc
M	source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc

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

diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 98f5de43f84..317d513dae6 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -580,6 +580,9 @@ class InstancesComponent : public GeometryComponent {
 
   blender::Span<InstanceReference> references() const;
 
+  void ensure_geometry_instances();
+  GeometrySet &geometry_set_from_reference(const int reference_index);
+
   blender::Span<int> instance_reference_handles() const;
   blender::MutableSpan<int> instance_reference_handles();
   blender::MutableSpan<blender::float4x4> instance_transforms();
@@ -588,6 +591,7 @@ class InstancesComponent : public GeometryComponent {
   blender::Span<int> instance_ids() const;
 
   int instances_amount() const;
+  int references_amount() const;
 
   blender::Span<int> almost_unique_ids() const;
 
diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc
index c4e1fe2f8e9..4c10f5398b7 100644
--- a/source/blender/blenkernel/intern/geometry_component_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_component_instances.cc
@@ -24,6 +24,7 @@
 #include "DNA_collection_types.h"
 
 #include "BKE_geometry_set.hh"
+#include "BKE_geometry_set_instances.hh"
 
 #include "attribute_access_intern.hh"
 
@@ -32,6 +33,7 @@ using blender::Map;
 using blender::MutableSpan;
 using blender::Set;
 using blender::Span;
+using blender::VectorSet;
 
 /* -------------------------------------------------------------------- */
 /** \name Geometry Component Implementation
@@ -119,6 +121,52 @@ blender::Span<int> InstancesComponent::instance_ids() const
   return instance_ids_;
 }
 
+/**
+ * If references have a collection or object type, convert them into geometry instances. This
+ * will join geometry components from nested instances if necessary. After that, the geometry
+ * sets can be edited.
+ */
+void InstancesComponent::ensure_geometry_instances()
+{
+  VectorSet<InstanceReference> new_references;
+  new_references.reserve(references_.size());
+  for (const InstanceReference &reference : references_) {
+    if (reference.type() == InstanceReference::Type::Object) {
+      GeometrySet geometry_set;
+      InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+      const int handle = instances.add_reference(reference.object());
+      instances.add_instance(handle, float4x4::identity());
+      new_references.add_new(geometry_set);
+    }
+    else if (reference.type() == InstanceReference::Type::Collection) {
+      GeometrySet geometry_set;
+      InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+      const int handle = instances.add_reference(reference.collection());
+      instances.add_instance(handle, float4x4::identity());
+      new_references.add_new(geometry_set);
+    }
+    else {
+      new_references.add_new(reference);
+    }
+  }
+  references_ = std::move(new_references);
+}
+
+/**
+ * With write access to the instances component, the data in the instanced geometry sets can be
+ * changed. This is a function on the component rather than each reference to ensure const
+ * correct-ness for that reason.
+ */
+GeometrySet &InstancesComponent::geometry_set_from_reference(const int reference_index)
+{
+  /* If this assert fails, it means #ensure_geometry_instances must be called first. */
+  BLI_assert(references_[reference_index].type() == InstanceReference::Type::GeometrySet);
+
+  /* The const cast is okay because the instance's hash in the set
+   * is not changed by adjusting the data inside the geometry set. */
+  return const_cast<GeometrySet &>(references_[reference_index].geometry_set());
+}
+
 /**
  * Returns a handle for the given reference.
  * If the reference exists already, the handle of the existing reference is returned.
@@ -139,6 +187,11 @@ int InstancesComponent::instances_amount() const
   return instance_transforms_.size();
 }
 
+int InstancesComponent::references_amount() const
+{
+  return references_.size();
+}
+
 bool InstancesComponent::is_empty() const
 {
   return this->instance_reference_handles_.size() == 0;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
index d8f40b0a0df..8de2975f9b0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
@@ -124,37 +124,55 @@ static Mesh *cdt_to_mesh(const blender::meshintersect::CDT_result<double> &resul
   return mesh;
 }
 
-static Mesh *curve_fill_calculate(GeoNodeExecParams &params, const CurveComponent &component)
+static void curve_fill_calculate(GeometrySet &geometry_set, const GeometryNodeCurveFillMode mode)
 {
-  const CurveEval &curve = *component.get_for_read();
-  if (curve.splines().size() == 0) {
-    return nullptr;
+  if (!geometry_set.has_curve()) {
+    return;
   }
 
-  const NodeGeometryCurveFill &storage = *(const NodeGeometryCurveFill *)params.node().storage;
-  const GeometryNodeCurveFillMode mode = (GeometryNodeCurveFillMode)storage.mode;
+  const CurveEval &curve = *geometry_set.get_curve_for_read();
+  if (curve.splines().is_empty()) {
+    geometry_set.replace_curve(nullptr);
+    return;
+  }
 
   const CDT_output_type output_type = (mode == GEO_NODE_CURVE_FILL_MODE_NGONS) ?
                                           CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES :
                                           CDT_INSIDE_WITH_HOLES;
 
   const blender::meshintersect::CDT_result<double> results = do_cdt(curve, output_type);
-  return cdt_to_mesh(results);
+  Mesh *mesh = cdt_to_mesh(results);
+
+  geometry_set.replace_mesh(mesh);
+  geometry_set.replace_curve(nullptr);
 }
 
 static void geo_node_curve_fill_exec(GeoNodeExecParams params)
 {
   GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
-  geometry_set = bke::geometry_set_realize_instances(geometry_set);
 
-  if (!geometry_set.has_curve()) {
-    params.set_output("Mesh", GeometrySet());
+  const NodeGeometryCurveFill &storage = *(const NodeGeometryCurveFill *)params.node().storage;
+  const GeometryNodeCurveFillMode mode = (GeometryNodeCurveFillMode)storage.mode;
+
+  if (geometry_set.has_instances()) {
+    InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+    instances.ensure_geometry_instances();
+
+    threading::parallel_for(IndexRange(instances.references_amount()), 16, [&](IndexRange range) {
+      for (int i : range) {
+        GeometrySet &geometry_set = instances.geometry_set_from_reference(i);
+        geometry_set = bke::geometry_set_realize_instances(geometry_set);
+        curve_fill_calculate(geometry_set, mode);
+      }
+    });
+
+    params.set_output("Mesh", std::move(geometry_set));
     return;
   }
 
-  Mesh *mesh = curve_fill_calculate(params,
-                                    *geometry_set.get_component_for_read<CurveComponent>());
-  params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
+  curve_fill_calculate(geometry_set, mode);
+
+  params.set_output("Mesh", std::move(geometry_set));
 }
 
 }  // namespace blender::nodes



More information about the Bf-blender-cvs mailing list