diff options
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 ¶ms, 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 |