Blender V4.5
instances.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_array_utils.hh"
6#include "BLI_listbase.h"
7#include "BLI_rand.hh"
8#include "BLI_task.hh"
9
11#include "DNA_object_types.h"
12
13#include "BKE_customdata.hh"
14#include "BKE_geometry_set.hh"
16#include "BKE_instances.hh"
17
18namespace blender::bke {
19
21 : type_(Type::GeometrySet),
22 geometry_set_(std::make_unique<GeometrySet>(std::move(geometry_set)))
23{
24}
25
27 : type_(other.type_), data_(other.data_)
28{
29 if (other.geometry_set_) {
30 geometry_set_ = std::make_unique<GeometrySet>(*other.geometry_set_);
31 }
32}
33
35{
36 if (type_ != Type::GeometrySet) {
37 return;
38 }
39 geometry_set_->ensure_owns_direct_data();
40}
41
43{
44 if (type_ != Type::GeometrySet) {
45 /* The object and collection instances are not direct data. */
46 return true;
47 }
48 return geometry_set_->owns_direct_data();
49}
50
52{
53 switch (type_) {
54 case Type::GeometrySet: {
55 geometry_set_->count_memory(memory);
56 }
57 default: {
58 break;
59 }
60 }
61}
62
67
72
73static void convert_collection_to_instances(const Collection &collection,
74 bke::Instances &instances)
75{
76 LISTBASE_FOREACH (CollectionChild *, collection_child, &collection.children) {
78 transform.location() += float3(collection_child->collection->instance_offset);
79 transform.location() -= float3(collection.instance_offset);
80 const int handle = instances.add_reference(*collection_child->collection);
81 instances.add_instance(handle, transform);
82 }
83
84 LISTBASE_FOREACH (CollectionObject *, collection_object, &collection.gobject) {
86 transform.location() -= float3(collection.instance_offset);
87 transform *= (collection_object->ob)->object_to_world();
88 const int handle = instances.add_reference(*collection_object->ob);
89 instances.add_instance(handle, transform);
90 }
91}
92
94{
95 r_geometry_set.clear();
96 switch (type_) {
97 case Type::Object: {
98 const Object &object = this->object();
99 r_geometry_set = bke::object_get_evaluated_geometry_set(object);
100 break;
101 }
102 case Type::Collection: {
103 const Collection &collection = this->collection();
104 std::unique_ptr<bke::Instances> instances_ptr = std::make_unique<bke::Instances>();
106 r_geometry_set.replace_instances(instances_ptr.release());
107 break;
108 }
109 case Type::GeometrySet: {
110 r_geometry_set = this->geometry_set();
111 break;
112 }
113 case Type::None: {
114 break;
115 }
116 }
117}
118
120{
121 switch (type_) {
122 case Type::Object:
123 return this->object().id.name + 2;
124 case Type::Collection:
125 return this->collection().id.name + 2;
127 return this->geometry_set().name;
128 case Type::None:
129 break;
130 }
131 return "";
132}
133
135{
136 if (a.geometry_set_ && b.geometry_set_) {
137 return *a.geometry_set_ == *b.geometry_set_;
138 }
139 return a.type_ == b.type_ && a.data_ == b.data_;
140}
141
143{
144 const uint64_t geometry_hash = geometry_set_ ? geometry_set_->hash() : 0;
145 return get_default_hash(geometry_hash, type_, data_);
146}
147
149{
150 CustomData_reset(&attributes_);
151}
152
154 : references_(std::move(other.references_)),
155 instances_num_(other.instances_num_),
156 attributes_(other.attributes_),
157 reference_user_counts_(std::move(other.reference_user_counts_)),
158 almost_unique_ids_cache_(std::move(other.almost_unique_ids_cache_))
159{
160 CustomData_reset(&other.attributes_);
161}
162
164 : references_(other.references_),
165 instances_num_(other.instances_num_),
166 reference_user_counts_(other.reference_user_counts_),
167 almost_unique_ids_cache_(other.almost_unique_ids_cache_)
168{
169 CustomData_init_from(&other.attributes_, &attributes_, CD_MASK_ALL, other.instances_num_);
170}
171
173{
174 CustomData_free(&attributes_);
175}
176
178{
179 if (this == &other) {
180 return *this;
181 }
182 std::destroy_at(this);
183 new (this) Instances(other);
184 return *this;
185}
186
188{
189 if (this == &other) {
190 return *this;
191 }
192 std::destroy_at(this);
193 new (this) Instances(std::move(other));
194 return *this;
195}
196
197void Instances::resize(int capacity)
198{
199 CustomData_realloc(&attributes_, instances_num_, capacity, CD_SET_DEFAULT);
200 instances_num_ = capacity;
201}
202
203void Instances::add_instance(const int instance_handle, const float4x4 &transform)
204{
205 BLI_assert(instance_handle >= 0);
206 BLI_assert(instance_handle < references_.size());
207 const int old_size = instances_num_;
208 instances_num_++;
209 CustomData_realloc(&attributes_, old_size, instances_num_);
210 this->reference_handles_for_write().last() = instance_handle;
211 this->transforms_for_write().last() = transform;
213}
214
216{
217 return {static_cast<const int *>(
218 CustomData_get_layer_named(&attributes_, CD_PROP_INT32, ".reference_index")),
219 instances_num_};
220}
221
223{
224 int *data = static_cast<int *>(CustomData_get_layer_named_for_write(
225 &attributes_, CD_PROP_INT32, ".reference_index", instances_num_));
226 if (!data) {
227 data = static_cast<int *>(CustomData_add_layer_named(
228 &attributes_, CD_PROP_INT32, CD_SET_DEFAULT, instances_num_, ".reference_index"));
229 }
230 return {data, instances_num_};
231}
232
234{
235 return {static_cast<const float4x4 *>(
236 CustomData_get_layer_named(&attributes_, CD_PROP_FLOAT4X4, "instance_transform")),
237 instances_num_};
238}
239
241{
243 &attributes_, CD_PROP_FLOAT4X4, "instance_transform", instances_num_));
244 if (!data) {
246 &attributes_, CD_PROP_FLOAT4X4, CD_SET_DEFAULT, instances_num_, "instance_transform"));
247 }
248 return {data, instances_num_};
249}
250
252{
253 /* If this assert fails, it means #ensure_geometry_instances must be called first or that the
254 * reference can't be converted to a geometry set. */
255 BLI_assert(references_[reference_index].type() == InstanceReference::Type::GeometrySet);
256
257 return references_[reference_index].geometry_set();
258}
259
261{
262 for (const int i : references_.index_range()) {
263 const InstanceReference &reference = references_[i];
264 if (reference == query) {
265 return i;
266 }
267 }
268 return std::nullopt;
269}
270
272{
273 if (std::optional<int> handle = this->find_reference_handle(reference)) {
274 return *handle;
275 }
276 return this->add_new_reference(reference);
277}
278
280{
282 return references_.append_and_get_index(reference);
283}
284
286{
287 return references_;
288}
289
290void Instances::remove(const IndexMask &mask, const AttributeFilter &attribute_filter)
291{
292 const std::optional<IndexRange> masked_range = mask.to_range();
293 if (masked_range.has_value() && masked_range->start() == 0) {
294 /* Deleting from the end of the array can be much faster since no data has to be shifted. */
295 this->resize(mask.size());
297 return;
298 }
299
300 Instances new_instances;
301 new_instances.references_ = std::move(references_);
302 new_instances.instances_num_ = mask.size();
303
307 attribute_filter,
308 mask,
309 new_instances.attributes_for_write());
310
311 *this = std::move(new_instances);
312
314}
315
317{
318 const int tot_instances = instances_num_;
319 const int tot_references_before = references_.size();
320
321 if (tot_instances == 0) {
322 /* If there are no instances, no reference is needed. */
323 references_.clear();
324 return;
325 }
326 if (tot_references_before == 1) {
327 /* There is only one reference and at least one instance. So the only existing reference is
328 * used. Nothing to do here. */
329 return;
330 }
331
333
334 Array<bool> usage_by_handle(tot_references_before, false);
335 Mutex mutex;
336
337 /* Loop over all instances to see which references are used. */
338 threading::parallel_for(IndexRange(tot_instances), 1000, [&](IndexRange range) {
339 /* Use local counter to avoid lock contention. */
340 Array<bool> local_usage_by_handle(tot_references_before, false);
341
342 for (const int i : range) {
343 const int handle = reference_handles[i];
344 BLI_assert(handle >= 0 && handle < tot_references_before);
345 local_usage_by_handle[handle] = true;
346 }
347
348 std::lock_guard lock{mutex};
349 for (const int i : IndexRange(tot_references_before)) {
350 usage_by_handle[i] |= local_usage_by_handle[i];
351 }
352 });
353
354 if (!usage_by_handle.as_span().contains(false)) {
355 /* All references are used. */
356 return;
357 }
358
359 /* Create new references and a mapping for the handles. */
360 Vector<int> handle_mapping;
361 Vector<InstanceReference> new_references;
362 int next_new_handle = 0;
363 bool handles_have_to_be_updated = false;
364 for (const int old_handle : IndexRange(tot_references_before)) {
365 if (!usage_by_handle[old_handle]) {
366 /* Add some dummy value. It won't be read again. */
367 handle_mapping.append(-1);
368 }
369 else {
370 const InstanceReference &reference = references_[old_handle];
371 handle_mapping.append(next_new_handle);
372 new_references.append(reference);
373 if (old_handle != next_new_handle) {
374 handles_have_to_be_updated = true;
375 }
376 next_new_handle++;
377 }
378 }
379 references_ = new_references;
380
381 if (!handles_have_to_be_updated) {
382 /* All remaining handles are the same as before, so they don't have to be updated. This happens
383 * when unused handles are only at the end. */
384 return;
385 }
386
387 /* Update handles of instances. */
388 {
390 threading::parallel_for(IndexRange(tot_instances), 1000, [&](IndexRange range) {
391 for (const int i : range) {
392 reference_handles[i] = handle_mapping[reference_handles[i]];
393 }
394 });
395 }
396}
397
399{
400 return this->instances_num_;
401}
402
404{
405 return references_.size();
406}
407
409{
410 for (const InstanceReference &reference : references_) {
411 if (!reference.owns_direct_data()) {
412 return false;
413 }
414 }
415 return true;
416}
417
419{
420 for (const InstanceReference &const_reference : references_) {
421 /* `const` cast is fine because we are not changing anything that would change the hash of the
422 * reference. */
423 InstanceReference &reference = const_cast<InstanceReference &>(const_reference);
424 reference.ensure_owns_direct_data();
425 }
426}
427
429{
430 CustomData_count_memory(attributes_, instances_num_, memory);
431 for (const InstanceReference &reference : references_) {
432 reference.count_memory(memory);
433 }
434}
435
437{
438 Array<int> unique_ids(original_ids.size());
439
440 Set<int> used_unique_ids;
441 used_unique_ids.reserve(original_ids.size());
442 Vector<int> instances_with_id_collision;
443 for (const int instance_index : original_ids.index_range()) {
444 const int original_id = original_ids[instance_index];
445 if (used_unique_ids.add(original_id)) {
446 /* The original id has not been used by another instance yet. */
447 unique_ids[instance_index] = original_id;
448 }
449 else {
450 /* The original id of this instance collided with a previous instance, it needs to be looked
451 * at again in a second pass. Don't generate a new random id here, because this might collide
452 * with other existing ids. */
453 instances_with_id_collision.append(instance_index);
454 }
455 }
456
457 Map<int, RandomNumberGenerator> generator_by_original_id;
458 for (const int instance_index : instances_with_id_collision) {
459 const int original_id = original_ids[instance_index];
460 RandomNumberGenerator &rng = generator_by_original_id.lookup_or_add_cb(original_id, [&]() {
462 rng.seed_random(original_id);
463 return rng;
464 });
465
466 const int max_iteration = 100;
467 for (int iteration = 0;; iteration++) {
468 /* Try generating random numbers until an unused one has been found. */
469 const int random_id = rng.get_int32();
470 if (used_unique_ids.add(random_id)) {
471 /* This random id is not used by another instance. */
472 unique_ids[instance_index] = random_id;
473 break;
474 }
475 if (iteration == max_iteration) {
476 /* It seems to be very unlikely that we ever run into this case (assuming there are less
477 * than 2^30 instances). However, if that happens, it's better to use an id that is not
478 * unique than to be stuck in an infinite loop. */
479 unique_ids[instance_index] = original_id;
480 break;
481 }
482 }
483 }
484
485 return unique_ids;
486}
487
489{
490 reference_user_counts_.ensure([&](Array<int> &r_data) {
491 const int references_num = references_.size();
493 r_data.fill(0);
494
495 const Span<int> handles = this->reference_handles();
496 for (const int handle : handles) {
497 if (handle >= 0 && handle < references_num) {
498 r_data[handle]++;
499 }
500 }
501 });
502 return reference_user_counts_.data();
503}
504
506{
507 almost_unique_ids_cache_.ensure([&](Array<int> &r_data) {
508 const VArraySpan<int> instance_ids = *this->attributes().lookup<int>("id");
509 if (instance_ids.is_empty()) {
510 r_data.reinitialize(instances_num_);
512 return;
513 }
514 r_data = generate_unique_instance_ids(instance_ids);
515 });
516 return almost_unique_ids_cache_.data();
517}
518
520{
521 return transform.location();
522}
523
524static void set_transform_position(float4x4 &transform, const float3 position)
525{
526 transform.location() = position;
527}
528
533
540
541} // namespace blender::bke
CustomData interface, see also DNA_customdata_types.h.
void CustomData_count_memory(const CustomData &data, int totelem, blender::MemoryCounter &memory)
void CustomData_realloc(CustomData *data, int old_size, int new_size, eCDAllocType alloctype=CD_CONSTRUCT)
void * CustomData_get_layer_named_for_write(CustomData *data, eCustomDataType type, blender::StringRef name, int totelem)
@ CD_SET_DEFAULT
const void * CustomData_get_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
void * CustomData_add_layer_named(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem, blender::StringRef name)
void CustomData_reset(CustomData *data)
void CustomData_free(CustomData *data)
void CustomData_init_from(const CustomData *source, CustomData *dest, eCustomDataMask mask, int totelem)
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
Object groups, one object can be in many groups at once.
@ CD_PROP_INT32
@ CD_PROP_FLOAT4X4
Object is a sort of wrapper for general info.
volatile int lock
BMesh const char void * data
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
unsigned long long int uint64_t
constexpr T & last(const int64_t n=0) const
Definition BLI_span.hh:689
constexpr const T * data() const
Definition BLI_span.hh:215
Span< T > as_span() const
Definition BLI_array.hh:232
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:237
void fill(const T &value) const
Definition BLI_array.hh:261
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:398
Value & lookup_or_add_cb(const Key &key, const CreateValueF &create_value)
Definition BLI_map.hh:620
void seed_random(uint32_t seed)
Definition rand.cc:297
void reserve(const int64_t n)
Definition BLI_set.hh:637
bool add(const Key &key)
Definition BLI_set.hh:248
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
static VArray ForDerivedSpan(Span< StructT > values)
static VMutableArray ForDerivedSpan(MutableSpan< StructT > values)
int64_t size() const
void append(const T &value)
GAttributeReader lookup(const StringRef attribute_id) const
void count_memory(MemoryCounter &memory) const
Definition instances.cc:51
void to_geometry_set(GeometrySet &r_geometry_set) const
Definition instances.cc:93
StringRefNull name() const
Definition instances.cc:119
Collection & collection() const
Span< int > reference_handles() const
Definition instances.cc:215
MutableSpan< int > reference_handles_for_write()
Definition instances.cc:222
int add_reference(const InstanceReference &reference)
Definition instances.cc:271
void remove(const IndexMask &mask, const AttributeFilter &attribute_filter)
Definition instances.cc:290
int add_new_reference(const InstanceReference &reference)
Definition instances.cc:279
GeometrySet & geometry_set_from_reference(int reference_index)
Definition instances.cc:251
Span< float4x4 > transforms() const
Definition instances.cc:233
void add_instance(int instance_handle, const float4x4 &transform)
Definition instances.cc:203
Span< InstanceReference > references() const
Definition instances.cc:285
Span< int > reference_user_counts() const
Definition instances.cc:488
Instances & operator=(const Instances &other)
Definition instances.cc:177
void resize(int capacity)
Definition instances.cc:197
int references_num() const
Definition instances.cc:403
bke::MutableAttributeAccessor attributes_for_write()
Definition instances.cc:68
bke::AttributeAccessor attributes() const
Definition instances.cc:63
int instances_num() const
Definition instances.cc:398
void count_memory(MemoryCounter &memory) const
Definition instances.cc:428
Span< int > almost_unique_ids() const
Definition instances.cc:505
bool owns_direct_data() const
Definition instances.cc:408
std::optional< int > find_reference_handle(const InstanceReference &query)
Definition instances.cc:260
MutableSpan< float4x4 > transforms_for_write()
Definition instances.cc:240
ThreadMutex mutex
#define CD_MASK_ALL
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
void fill_index_range(MutableSpan< T > span, const T start=0)
static void convert_collection_to_instances(const Collection &collection, bke::Instances &instances)
Definition instances.cc:73
bool operator==(const InstanceReference &a, const InstanceReference &b)
Definition instances.cc:134
void gather_attributes(AttributeAccessor src_attributes, AttrDomain src_domain, AttrDomain dst_domain, const AttributeFilter &attribute_filter, const IndexMask &selection, MutableAttributeAccessor dst_attributes)
static float3 get_transform_position(const float4x4 &transform)
Definition instances.cc:519
GeometrySet object_get_evaluated_geometry_set(const Object &object, bool apply_subdiv=true)
VArray< float3 > instance_position_varray(const Instances &instances)
Definition instances.cc:529
static Array< int > generate_unique_instance_ids(Span< int > original_ids)
Definition instances.cc:436
VMutableArray< float3 > instance_position_varray_for_write(Instances &instances)
Definition instances.cc:534
static void set_transform_position(float4x4 &transform, const float3 position)
Definition instances.cc:524
const AttributeAccessorFunctions & instance_attribute_accessor_functions()
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
MatBase< float, 4, 4 > float4x4
uint64_t get_default_hash(const T &v, const Args &...args)
Definition BLI_hash.hh:233
std::mutex Mutex
Definition BLI_mutex.hh:47
VecBase< float, 3 > float3
char name[66]
Definition DNA_ID.h:415
void replace_instances(Instances *instances, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
i
Definition text_draw.cc:230
ParamHandle ** handles