Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Goudey <h.goudey@me.com>2021-09-21 22:20:54 +0300
committerHans Goudey <h.goudey@me.com>2021-09-21 22:20:54 +0300
commit6d162d35e2c85ea4fb990f0c459ec36064cf0550 (patch)
treea0e5f89fdfedf77eb21439438760b2cffb7ba94f /source/blender
parent29e3545194804428676b0adf881f418a96a40a9a (diff)
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
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh4
-rw-r--r--source/blender/blenkernel/intern/geometry_component_instances.cc53
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc44
3 files changed, 88 insertions, 13 deletions
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
@@ -120,6 +122,52 @@ blender::Span<int> InstancesComponent::instance_ids() const
}
/**
+ * 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.
* Otherwise a new handle is added.
@@ -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