diff options
Diffstat (limited to 'source/blender/blenkernel/intern/geometry_component_instances.cc')
-rw-r--r-- | source/blender/blenkernel/intern/geometry_component_instances.cc | 175 |
1 files changed, 46 insertions, 129 deletions
diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc index 9a30c86c1e5..93a7646fed0 100644 --- a/source/blender/blenkernel/intern/geometry_component_instances.cc +++ b/source/blender/blenkernel/intern/geometry_component_instances.cc @@ -31,12 +31,17 @@ #include "attribute_access_intern.hh" +#include "FN_cpp_type_make.hh" + using blender::float4x4; using blender::Map; using blender::MutableSpan; using blender::Set; using blender::Span; using blender::VectorSet; +using blender::fn::GSpan; + +MAKE_CPP_TYPE(InstanceReference, InstanceReference, CPPTypeFlags::None) /* -------------------------------------------------------------------- */ /** \name Geometry Component Implementation @@ -51,8 +56,8 @@ GeometryComponent *InstancesComponent::copy() const InstancesComponent *new_component = new InstancesComponent(); new_component->instance_reference_handles_ = instance_reference_handles_; new_component->instance_transforms_ = instance_transforms_; - new_component->instance_ids_ = instance_ids_; new_component->references_ = references_; + new_component->attributes_ = attributes_; return new_component; } @@ -60,32 +65,21 @@ void InstancesComponent::reserve(int min_capacity) { instance_reference_handles_.reserve(min_capacity); instance_transforms_.reserve(min_capacity); - if (!instance_ids_.is_empty()) { - this->instance_ids_ensure(); - } + attributes_.reallocate(min_capacity); } -/** - * Resize the transform, handles, and ID vectors to the specified capacity. - * - * \note This function should be used carefully, only when it's guaranteed - * that the data will be filled. - */ void InstancesComponent::resize(int capacity) { instance_reference_handles_.resize(capacity); instance_transforms_.resize(capacity); - if (!instance_ids_.is_empty()) { - this->instance_ids_ensure(); - } + attributes_.reallocate(capacity); } void InstancesComponent::clear() { instance_reference_handles_.clear(); instance_transforms_.clear(); - instance_ids_.clear(); - + attributes_.clear(); references_.clear(); } @@ -95,9 +89,7 @@ void InstancesComponent::add_instance(const int instance_handle, const float4x4 BLI_assert(instance_handle < references_.size()); instance_reference_handles_.append(instance_handle); instance_transforms_.append(transform); - if (!instance_ids_.is_empty()) { - this->instance_ids_ensure(); - } + attributes_.reallocate(this->instances_amount()); } blender::Span<int> InstancesComponent::instance_reference_handles() const @@ -119,36 +111,6 @@ blender::Span<blender::float4x4> InstancesComponent::instance_transforms() const return instance_transforms_; } -blender::MutableSpan<int> InstancesComponent::instance_ids() -{ - return instance_ids_; -} -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` - * correctness 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 or that the @@ -160,11 +122,6 @@ GeometrySet &InstancesComponent::geometry_set_from_reference(const int reference 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. - */ int InstancesComponent::add_reference(const InstanceReference &reference) { return references_.index_of_or_add_as(reference); @@ -347,15 +304,17 @@ 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 (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; + std::optional<GSpan> instance_ids_gspan = attributes_.get_for_read("id"); + if (instance_ids_gspan) { + Span<int> instance_ids = instance_ids_gspan->typed<int>(); + if (almost_unique_ids_.size() != instance_ids.size()) { + almost_unique_ids_ = generate_unique_instance_ids(instance_ids); } } else { - if (almost_unique_ids_.size() != instance_ids_.size()) { - almost_unique_ids_ = generate_unique_instance_ids(instance_ids_); + almost_unique_ids_.reinitialize(this->instances_amount()); + for (const int i : almost_unique_ids_.index_range()) { + almost_unique_ids_[i] = i; } } return almost_unique_ids_; @@ -434,81 +393,21 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider } }; -class InstanceIDAttributeProvider final : public BuiltinAttributeProvider { - public: - InstanceIDAttributeProvider() - : BuiltinAttributeProvider( - "id", ATTR_DOMAIN_INSTANCE, CD_PROP_INT32, Creatable, Writable, Deletable) - { - } - - GVArray 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 VArray<int>::ForSpan(instances.instance_ids()); - } - - WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final - { - InstancesComponent &instances = static_cast<InstancesComponent &>(component); - if (instances.instance_ids().is_empty()) { - return {}; - } - return {VMutableArray<int>::ForSpan(instances.instance_ids()), domain_}; - } - - 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(varray.index_range(), 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; - } +template<typename T> +static GVArray make_array_read_attribute(const void *data, const int domain_size) +{ + return VArray<T>::ForSpan(Span<T>((const T *)data, domain_size)); +} - bool exists(const GeometryComponent &component) const final - { - const InstancesComponent &instances = static_cast<const InstancesComponent &>(component); - return !instances.instance_ids().is_empty(); - } -}; +template<typename T> +static GVMutableArray make_array_write_attribute(void *data, const int domain_size) +{ + return VMutableArray<T>::ForSpan(MutableSpan<T>((T *)data, domain_size)); +} static ComponentAttributeProviders create_attribute_providers_for_instances() { static InstancePositionAttributeProvider position; - static InstanceIDAttributeProvider id; - static CustomDataAccessInfo instance_custom_data_access = { [](GeometryComponent &component) -> CustomData * { InstancesComponent &inst = static_cast<InstancesComponent &>(component); @@ -520,6 +419,24 @@ static ComponentAttributeProviders create_attribute_providers_for_instances() }, nullptr}; + /** + * IDs of the instances. They are used for consistency over multiple frames for things like + * 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. + */ + static BuiltinCustomDataLayerProvider id("id", + ATTR_DOMAIN_INSTANCE, + CD_PROP_INT32, + CD_PROP_INT32, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + instance_custom_data_access, + make_array_read_attribute<int>, + make_array_write_attribute<int>, + nullptr); + static CustomDataAttributeProvider instance_custom_data(ATTR_DOMAIN_INSTANCE, instance_custom_data_access); |