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:
Diffstat (limited to 'source/blender/blenkernel/intern/geometry_component_instances.cc')
-rw-r--r--source/blender/blenkernel/intern/geometry_component_instances.cc175
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);