diff options
Diffstat (limited to 'source/blender')
9 files changed, 151 insertions, 34 deletions
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 @@ -125,6 +129,22 @@ blender::Span<int> InstancesComponent::instance_ids() const } /** + * 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` * correctness for that reason. @@ -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(InstancesComponent &instances, instances.resize(start_len + domain_size); MutableSpan<int> handles = instances.instance_reference_handles().slice(start_len, domain_size); MutableSpan<float4x4> transforms = instances.instance_transforms().slice(start_len, domain_size); - MutableSpan<int> instance_ids = instances.instance_ids().slice(start_len, domain_size); + MutableSpan<int> instance_ids = instances.instance_ids_ensure().slice(start_len, domain_size); /* Skip all of the randomness handling if there is only a single possible instance * (anything except for collection mode with "Whole Collection" turned off). */ diff --git a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc index 44cad2d38d4..f4a127faf43 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc @@ -77,7 +77,6 @@ static void add_instances_from_component(InstancesComponent &dst_component, select_len); MutableSpan<float4x4> dst_transforms = dst_component.instance_transforms().slice(start_len, select_len); - MutableSpan<int> dst_stable_ids = dst_component.instance_ids().slice(start_len, select_len); FieldEvaluator field_evaluator{field_context, domain_size}; const VArray<bool> *pick_instance = nullptr; @@ -86,7 +85,6 @@ static void add_instances_from_component(InstancesComponent &dst_component, const VArray<float3> *scales = nullptr; /* The evaluator could use the component's stable IDs as a destination directly, but only the * selected indices should be copied. */ - GVArray_Typed<int> stable_ids = src_component.attribute_get_for_read("id", ATTR_DOMAIN_POINT, 0); field_evaluator.add(params.get_input<Field<bool>>("Pick Instance"), &pick_instance); field_evaluator.add(params.get_input<Field<int>>("Instance Index"), &indices); field_evaluator.add(params.get_input<Field<float3>>("Rotation"), &rotations); @@ -119,7 +117,6 @@ static void add_instances_from_component(InstancesComponent &dst_component, threading::parallel_for(selection.index_range(), 1024, [&](IndexRange selection_range) { for (const int range_i : selection_range) { const int64_t i = selection[range_i]; - dst_stable_ids[range_i] = (*stable_ids)[i]; /* Compute base transform for every instances. */ float4x4 &dst_transform = dst_transforms[range_i]; @@ -157,6 +154,17 @@ static void add_instances_from_component(InstancesComponent &dst_component, } }); + GVArrayPtr id_attribute = src_component.attribute_try_get_for_read( + "id", ATTR_DOMAIN_POINT, CD_PROP_INT32); + if (id_attribute) { + GVArray_Typed<int> ids{*id_attribute}; + VArray_Span<int> ids_span{ids}; + MutableSpan<int> dst_ids = dst_component.instance_ids_ensure(); + for (const int64_t i : selection.index_range()) { + dst_ids[i] = ids_span[selection[i]]; + } + } + if (pick_instance->is_single()) { if (pick_instance->get_internal_single()) { if (instance.has_realized_data()) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc index 63d1f88a442..434fe4a19d7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc @@ -77,13 +77,15 @@ static void convert_instances_to_points(GeometrySet &geometry_set, const VArray<float> &radii = evaluator.get_evaluated<float>(1); copy_attribute_to_points(radii, selection, {pointcloud->radius, pointcloud->totpoint}); - OutputAttribute_Typed<int> id_attribute = points.attribute_try_get_for_output<int>( - "id", ATTR_DOMAIN_POINT, 0); - MutableSpan<int> ids = id_attribute.as_span(); - for (const int i : selection.index_range()) { - ids[i] = instances.instance_ids()[selection[i]]; + if (!instances.instance_ids().is_empty()) { + OutputAttribute_Typed<int> id_attribute = points.attribute_try_get_for_output<int>( + "id", ATTR_DOMAIN_POINT, CD_PROP_INT32); + MutableSpan<int> ids = id_attribute.as_span(); + for (const int i : selection.index_range()) { + ids[i] = instances.instance_ids()[selection[i]]; + } + id_attribute.save(); } - id_attribute.save(); } static void geo_node_instances_to_points_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc index b628c5cbab8..bbba8635b88 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -270,17 +270,16 @@ static void join_components(Span<const InstancesComponent *> src_components, Geo } Span<float4x4> src_transforms = src_component->instance_transforms(); - Span<int> src_ids = src_component->instance_ids(); Span<int> src_reference_handles = src_component->instance_reference_handles(); for (const int i : src_transforms.index_range()) { const int src_handle = src_reference_handles[i]; const int dst_handle = handle_map[src_handle]; const float4x4 &transform = src_transforms[i]; - const int id = src_ids[i]; - dst_component.add_instance(dst_handle, transform, id); + dst_component.add_instance(dst_handle, transform); } } + join_attributes(to_base_components(src_components), dst_component, {"position"}); } static void join_components(Span<const VolumeComponent *> src_components, GeometrySet &result) diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc index ac946540221..83526df3ac2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc @@ -242,13 +242,11 @@ static void add_instances_from_handles(InstancesComponent &instances, instances.resize(positions.size()); MutableSpan<int> handles = instances.instance_reference_handles(); MutableSpan<float4x4> transforms = instances.instance_transforms(); - MutableSpan<int> instance_ids = instances.instance_ids(); threading::parallel_for(IndexRange(positions.size()), 256, [&](IndexRange range) { for (const int i : range) { handles[i] = char_handles.lookup(charcodes[i]); transforms[i] = float4x4::from_location({positions[i].x, positions[i].y, 0}); - instance_ids[i] = i; } }); } |