diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index 8e36bda84ce..0f9c2c1062b 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -922,6 +922,11 @@ class InstancesComponent : public GeometryComponent { int instances_amount() const; int references_amount() const; + /** + * Remove the indices in the selection mask and remove unused instance references afterwards. + */ + void remove_instances(const blender::IndexMask selection); + blender::Span almost_unique_ids() const; blender::bke::CustomDataAttributes &attributes(); diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc index 93a7646fed0..a7e3c5b60dc 100644 --- a/source/blender/blenkernel/intern/geometry_component_instances.cc +++ b/source/blender/blenkernel/intern/geometry_component_instances.cc @@ -17,6 +17,7 @@ #include #include "BLI_float4x4.hh" +#include "BLI_index_mask.hh" #include "BLI_map.hh" #include "BLI_rand.hh" #include "BLI_set.hh" @@ -26,6 +27,8 @@ #include "DNA_collection_types.h" +#include "BKE_attribute_access.hh" +#include "BKE_attribute_math.hh" #include "BKE_geometry_set.hh" #include "BKE_geometry_set_instances.hh" @@ -34,6 +37,7 @@ #include "FN_cpp_type_make.hh" using blender::float4x4; +using blender::IndexMask; using blender::Map; using blender::MutableSpan; using blender::Set; @@ -132,6 +136,62 @@ blender::Span InstancesComponent::references() const return references_; } +template +static void copy_data_based_on_mask(Span src, MutableSpan dst, IndexMask mask) +{ + BLI_assert(src.data() != dst.data()); + using namespace blender; + threading::parallel_for(mask.index_range(), 1024, [&](IndexRange range) { + for (const int i : range) { + dst[i] = src[mask[i]]; + } + }); +} + +void InstancesComponent::remove_instances(const IndexMask selection) +{ + using namespace blender; + if (selection.is_range() && selection.index_range().first() == 0) { + /* Deleting from the end of the array can be much faster since no data has to be shifted. */ + this->resize(selection.size()); + this->remove_unused_references(); + return; + } + + Vector new_handles(selection.size()); + copy_data_based_on_mask(this->instance_reference_handles(), new_handles, selection); + instance_reference_handles_ = std::move(new_handles); + Vector new_transforms(selection.size()); + copy_data_based_on_mask(this->instance_transforms(), new_transforms, selection); + instance_transforms_ = std::move(new_transforms); + + const bke::CustomDataAttributes &src_attributes = attributes_; + + bke::CustomDataAttributes dst_attributes; + dst_attributes.reallocate(selection.size()); + + src_attributes.foreach_attribute( + [&](const bke::AttributeIDRef &id, const AttributeMetaData &meta_data) { + if (!id.should_be_kept()) { + return true; + } + + GSpan src = *src_attributes.get_for_read(id); + dst_attributes.create(id, meta_data.data_type); + fn::GMutableSpan dst = *dst_attributes.get_for_write(id); + + attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { + using T = decltype(dummy); + copy_data_based_on_mask(src.typed(), dst.typed(), selection); + }); + return true; + }, + ATTR_DOMAIN_INSTANCE); + + attributes_ = std::move(dst_attributes); + this->remove_unused_references(); +} + void InstancesComponent::remove_unused_references() { using namespace blender; diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc index a5197b23adb..7d41242b8bc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc @@ -529,6 +529,30 @@ static void separate_point_cloud_selection(GeometrySet &geometry_set, geometry_set.replace_pointcloud(pointcloud); } +static void separate_instance_selection(GeometrySet &geometry_set, + const Field &selection_field, + const bool invert) +{ + InstancesComponent &instances = geometry_set.get_component_for_write(); + GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE}; + + const int domain_size = instances.attribute_domain_size(ATTR_DOMAIN_INSTANCE); + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.add(selection_field); + evaluator.evaluate(); + const VArray_Span &selection = evaluator.get_evaluated(0); + + Vector indices; + const IndexMask mask = index_mask_indices(selection, invert, indices); + + if (mask.size() == 0) { + geometry_set.remove(); + return; + } + + instances.remove_instances(mask); +} + static void compute_selected_vertices_from_vertex_selection(const Span vertex_selection, const bool invert, MutableSpan r_vertex_map, @@ -1261,7 +1285,7 @@ void separate_geometry(GeometrySet &geometry_set, } } if (geometry_set.has_mesh()) { - if (domain != ATTR_DOMAIN_CURVE) { + if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER)) { separate_mesh_selection(geometry_set, selection_field, domain, mode, invert); some_valid_domain = true; } @@ -1272,6 +1296,12 @@ void separate_geometry(GeometrySet &geometry_set, some_valid_domain = true; } } + if (geometry_set.has_instances()) { + if (domain == ATTR_DOMAIN_INSTANCE) { + separate_instance_selection(geometry_set, selection_field, invert); + some_valid_domain = true; + } + } r_is_error = !some_valid_domain && geometry_set.has_realized_data(); }