[Bf-blender-cvs] [9fa304bf13e] master: Geometry Nodes: Only create instance IDs when they exist

Hans Goudey noreply at git.blender.org
Tue Oct 26 19:50:47 CEST 2021


Commit: 9fa304bf13e402405351a2c9bc14903c08b557e5
Author: Hans Goudey
Date:   Tue Oct 26 12:50:39 2021 -0500
Branches: master
https://developer.blender.org/rB9fa304bf13e402405351a2c9bc14903c08b557e5

Geometry Nodes: Only create instance IDs when they exist

Instance IDs serve no purpose for rendering when they aren't stable from
one frame to the next, and if the index is used in the end anyway, there
is no point in storing a vector of IDs and copying it around.

This commit exposes the `id` attribute on the instances component,
makes it optional-- only generated by default with the distribute points
on faces node.

Since the string to curves node only added the index as each instance's
ID, I removed it. This means that it would be necessary to add the ID
data manually if the initial index actually helps (when deleting only
certain characters, for example).

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

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

M	source/blender/blenkernel/BKE_geometry_set.hh
M	source/blender/blenkernel/intern/geometry_component_instances.cc
M	source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
M	source/blender/modifiers/intern/MOD_nodes.cc
M	source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.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_join_geometry.cc
M	source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc

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

diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 78ccefaed5c..429c37e9c9b 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -621,7 +621,9 @@ class InstancesComponent : public GeometryComponent {
   blender::Vector<blender::float4x4> instance_transforms_;
   /**
    * IDs of the instances. They are used for consistency over multiple frames for things like
-   * motion blur.
+   * motion blur. Proper stable ID data that actually helps when rendering can only be generated
+   * in some situations, so this vector is allowed to be empty, in which case the index of each
+   * instance will be used for the final ID.
    */
   blender::Vector<int> instance_ids_;
 
@@ -643,7 +645,7 @@ class InstancesComponent : public GeometryComponent {
   void resize(int capacity);
 
   int add_reference(const InstanceReference &reference);
-  void add_instance(int instance_handle, const blender::float4x4 &transform, const int id = -1);
+  void add_instance(int instance_handle, const blender::float4x4 &transform);
 
   blender::Span<InstanceReference> references() const;
   void remove_unused_references();
@@ -658,6 +660,9 @@ class InstancesComponent : public GeometryComponent {
   blender::MutableSpan<int> instance_ids();
   blender::Span<int> instance_ids() const;
 
+  blender::MutableSpan<int> instance_ids_ensure();
+  void instance_ids_clear();
+
   int instances_amount() const;
   int references_amount() const;
 
diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc
index 4204d62e1a7..d02121b44a6 100644
--- a/source/blender/blenkernel/intern/geometry_component_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_component_instances.cc
@@ -60,7 +60,9 @@ void InstancesComponent::reserve(int min_capacity)
 {
   instance_reference_handles_.reserve(min_capacity);
   instance_transforms_.reserve(min_capacity);
-  instance_ids_.reserve(min_capacity);
+  if (!instance_ids_.is_empty()) {
+    this->instance_ids_ensure();
+  }
 }
 
 /**
@@ -73,7 +75,9 @@ void InstancesComponent::resize(int capacity)
 {
   instance_reference_handles_.resize(capacity);
   instance_transforms_.resize(capacity);
-  instance_ids_.resize(capacity);
+  if (!instance_ids_.is_empty()) {
+    this->instance_ids_ensure();
+  }
 }
 
 void InstancesComponent::clear()
@@ -85,15 +89,15 @@ void InstancesComponent::clear()
   references_.clear();
 }
 
-void InstancesComponent::add_instance(const int instance_handle,
-                                      const float4x4 &transform,
-                                      const int id)
+void InstancesComponent::add_instance(const int instance_handle, const float4x4 &transform)
 {
   BLI_assert(instance_handle >= 0);
   BLI_assert(instance_handle < references_.size());
   instance_reference_handles_.append(instance_handle);
   instance_transforms_.append(transform);
-  instance_ids_.append(id);
+  if (!instance_ids_.is_empty()) {
+    this->instance_ids_ensure();
+  }
 }
 
 blender::Span<int> InstancesComponent::instance_reference_handles() const
@@ -124,6 +128,22 @@ blender::Span<int> InstancesComponent::instance_ids() const
   return instance_ids_;
 }
 
+/**
+ * Make sure the ID storage size matches the number of instances. By directly resizing the
+ * component's vectors internally, it is possible to be in a situation where the IDs are not
+ * empty but they do not have the correct size; this function resolves that.
+ */
+blender::MutableSpan<int> InstancesComponent::instance_ids_ensure()
+{
+  instance_ids_.append_n_times(0, this->instances_amount() - instance_ids_.size());
+  return instance_ids_;
+}
+
+void InstancesComponent::instance_ids_clear()
+{
+  instance_ids_.clear_and_make_inline();
+}
+
 /**
  * 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`
@@ -327,8 +347,16 @@ static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
 blender::Span<int> InstancesComponent::almost_unique_ids() const
 {
   std::lock_guard lock(almost_unique_ids_mutex_);
-  if (almost_unique_ids_.size() != instance_ids_.size()) {
-    almost_unique_ids_ = generate_unique_instance_ids(instance_ids_);
+  if (instance_ids().is_empty()) {
+    almost_unique_ids_.reinitialize(this->instances_amount());
+    for (const int i : almost_unique_ids_.index_range()) {
+      almost_unique_ids_[i] = i;
+    }
+  }
+  else {
+    if (almost_unique_ids_.size() != instance_ids_.size()) {
+      almost_unique_ids_ = generate_unique_instance_ids(instance_ids_);
+    }
   }
   return almost_unique_ids_;
 }
@@ -398,11 +426,82 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider
   }
 };
 
+class InstanceIDAttributeProvider final : public BuiltinAttributeProvider {
+ public:
+  InstanceIDAttributeProvider()
+      : BuiltinAttributeProvider(
+            "id", ATTR_DOMAIN_POINT, CD_PROP_INT32, Creatable, Writable, Deletable)
+  {
+  }
+
+  GVArrayPtr try_get_for_read(const GeometryComponent &component) const final
+  {
+    const InstancesComponent &instances = static_cast<const InstancesComponent &>(component);
+    if (instances.instance_ids().is_empty()) {
+      return {};
+    }
+    return std::make_unique<fn::GVArray_For_Span<int>>(instances.instance_ids());
+  }
+
+  GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const final
+  {
+    InstancesComponent &instances = static_cast<InstancesComponent &>(component);
+    if (instances.instance_ids().is_empty()) {
+      return {};
+    }
+    return std::make_unique<fn::GVMutableArray_For_MutableSpan<int>>(instances.instance_ids());
+  }
+
+  bool try_delete(GeometryComponent &component) const final
+  {
+    InstancesComponent &instances = static_cast<InstancesComponent &>(component);
+    if (instances.instance_ids().is_empty()) {
+      return false;
+    }
+    instances.instance_ids_clear();
+    return true;
+  }
+
+  bool try_create(GeometryComponent &component, const AttributeInit &initializer) const final
+  {
+    InstancesComponent &instances = static_cast<InstancesComponent &>(component);
+    if (instances.instances_amount() == 0) {
+      return false;
+    }
+    MutableSpan<int> ids = instances.instance_ids_ensure();
+    switch (initializer.type) {
+      case AttributeInit::Type::Default: {
+        ids.fill(0);
+        break;
+      }
+      case AttributeInit::Type::VArray: {
+        const GVArray *varray = static_cast<const AttributeInitVArray &>(initializer).varray;
+        varray->materialize_to_uninitialized(IndexRange(varray->size()), ids.data());
+        break;
+      }
+      case AttributeInit::Type::MoveArray: {
+        void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
+        ids.copy_from({static_cast<int *>(source_data), instances.instances_amount()});
+        MEM_freeN(source_data);
+        break;
+      }
+    }
+    return true;
+  }
+
+  bool exists(const GeometryComponent &component) const final
+  {
+    const InstancesComponent &instances = static_cast<const InstancesComponent &>(component);
+    return !instances.instance_ids().is_empty();
+  }
+};
+
 static ComponentAttributeProviders create_attribute_providers_for_instances()
 {
   static InstancePositionAttributeProvider position;
+  static InstanceIDAttributeProvider id;
 
-  return ComponentAttributeProviders({&position}, {});
+  return ComponentAttributeProviders({&position, &id}, {});
 }
 }  // namespace blender::bke
 
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
index 76e7291d905..f352a5fd0eb 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -466,14 +466,16 @@ std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
                                        });
   }
   Span<int> ids = component_->instance_ids();
-  if (STREQ(column_id.name, "ID")) {
-    /* Make the column a bit wider by default, since the IDs tend to be large numbers. */
-    return column_values_from_function(
-        SPREADSHEET_VALUE_TYPE_INT32,
-        column_id.name,
-        size,
-        [ids](int index, CellValue &r_cell_value) { r_cell_value.value_int = ids[index]; },
-        5.5f);
+  if (!ids.is_empty()) {
+    if (STREQ(column_id.name, "ID")) {
+      /* Make the column a bit wider by default, since the IDs tend to be large numbers. */
+      return column_values_from_function(
+          SPREADSHEET_VALUE_TYPE_INT32,
+          column_id.name,
+          size,
+          [ids](int index, CellValue &r_cell_value) { r_cell_value.value_int = ids[index]; },
+          5.5f);
+    }
   }
   return {};
 }
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index e6cc7663c58..292ba04490c 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -917,6 +917,10 @@ static void store_output_value_in_geometry(GeometrySet &geometry_set,
     CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
     store_field_on_geometry_component(component, attribute_name, domain, field);
   }
+  if (geometry_set.has_instances()) {
+    InstancesComponent &component = geometry_set.get_component_for_write<InstancesComponent>();
+    store_field_on_geometry_component(component, attribute_name, domain, field);
+  }
 }
 
 /**
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc
index fb45c22ced4..b68dfe44984 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc
@@ -184,7 +184,7 @@ static void add_instances_from_component(InstancesCompone

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list