Blender  V3.3
realize_instances.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
4 
5 #include "DNA_collection_types.h"
6 #include "DNA_layer_types.h"
7 #include "DNA_mesh_types.h"
8 #include "DNA_meshdata_types.h"
9 #include "DNA_object_types.h"
10 #include "DNA_pointcloud_types.h"
11 
12 #include "BLI_noise.hh"
13 #include "BLI_task.hh"
14 
15 #include "BKE_collection.h"
16 #include "BKE_curves.hh"
17 #include "BKE_deform.h"
19 #include "BKE_material.h"
20 #include "BKE_mesh.h"
21 #include "BKE_pointcloud.h"
22 #include "BKE_type_conversions.hh"
23 
24 namespace blender::geometry {
25 
34 
42 
43  int size() const
44  {
45  return this->kinds.size();
46  }
47 
49  {
50  return this->kinds.index_range();
51  }
52 };
53 
62 
64  {
65  }
66 };
67 
69  const PointCloud *pointcloud = nullptr;
75 };
76 
86  uint32_t id = 0;
87 };
88 
91  int vertex = 0;
92  int edge = 0;
93  int poly = 0;
94  int loop = 0;
95 };
96 
98  const Mesh *mesh = nullptr;
105 };
106 
114  uint32_t id = 0;
115 };
116 
118  const Curves *curves;
123 
126 
134 
140 
146 };
147 
150  int point = 0;
151  int curve = 0;
152 };
153 
156 
158  /* Transformation applied to the position of control points and handles. */
162  uint32_t id = 0;
163 };
164 
172  bool create_id_attribute = false;
173 };
174 
184  bool create_id_attribute = false;
185 };
186 
194  bool create_id_attribute = false;
198 };
199 
201 struct GatherTasks {
205 
206  /* Volumes only have very simple support currently. Only the first found volume is put into the
207  * output. */
210 };
211 
217 };
218 
225 
233 
238 };
239 
251  uint32_t id = 0;
252 
253  InstanceContext(const GatherTasksInfo &gather_info)
254  : pointclouds(gather_info.pointclouds.attributes.size()),
255  meshes(gather_info.meshes.attributes.size()),
256  curves(gather_info.curves.attributes.size())
257  {
258  }
259 };
260 
262  const float4x4 &transform,
264 {
265  threading::parallel_for(src.index_range(), 1024, [&](const IndexRange range) {
266  for (const int i : range) {
267  dst[i] = transform * src[i];
268  }
269  });
270 }
271 
272 static void threaded_copy(const GSpan src, GMutableSpan dst)
273 {
274  BLI_assert(src.size() == dst.size());
275  BLI_assert(src.type() == dst.type());
276  threading::parallel_for(IndexRange(src.size()), 1024, [&](const IndexRange range) {
277  src.type().copy_construct_n(src.slice(range).data(), dst.slice(range).data(), range.size());
278  });
279 }
280 
281 static void threaded_fill(const GPointer value, GMutableSpan dst)
282 {
283  BLI_assert(*value.type() == dst.type());
284  threading::parallel_for(IndexRange(dst.size()), 1024, [&](const IndexRange range) {
285  value.type()->fill_construct_n(value.get(), dst.slice(range).data(), range.size());
286  });
287 }
288 
290  const Span<std::optional<GVArraySpan>> src_attributes,
291  const AttributeFallbacksArray &attribute_fallbacks,
292  const OrderedAttributes &ordered_attributes,
293  const FunctionRef<IndexRange(eAttrDomain)> &range_fn,
294  MutableSpan<GSpanAttributeWriter> dst_attribute_writers)
295 {
297  dst_attribute_writers.index_range(), 10, [&](const IndexRange attribute_range) {
298  for (const int attribute_index : attribute_range) {
299  const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
300  const IndexRange element_slice = range_fn(domain);
301 
302  GMutableSpan dst_span = dst_attribute_writers[attribute_index].span.slice(element_slice);
303  if (src_attributes[attribute_index].has_value()) {
304  threaded_copy(*src_attributes[attribute_index], dst_span);
305  }
306  else {
307  const CPPType &cpp_type = dst_span.type();
308  const void *fallback = attribute_fallbacks.array[attribute_index] == nullptr ?
309  cpp_type.default_value() :
310  attribute_fallbacks.array[attribute_index];
311  threaded_fill({cpp_type, fallback}, dst_span);
312  }
313  }
314  });
315 }
316 
318  Span<int> stored_ids,
319  const int task_id,
320  MutableSpan<int> dst_ids)
321 {
322  if (options.keep_original_ids) {
323  if (stored_ids.is_empty()) {
324  dst_ids.fill(0);
325  }
326  else {
327  dst_ids.copy_from(stored_ids);
328  }
329  }
330  else {
331  if (stored_ids.is_empty()) {
332  threading::parallel_for(dst_ids.index_range(), 1024, [&](const IndexRange range) {
333  for (const int i : range) {
334  dst_ids[i] = noise::hash(task_id, i);
335  }
336  });
337  }
338  else {
339  threading::parallel_for(dst_ids.index_range(), 1024, [&](const IndexRange range) {
340  for (const int i : range) {
341  dst_ids[i] = noise::hash(task_id, stored_ids[i]);
342  }
343  });
344  }
345  }
346 }
347 
348 /* -------------------------------------------------------------------- */
352 /* Forward declaration. */
353 static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
354  const GeometrySet &geometry_set,
355  const float4x4 &base_transform,
356  const InstanceContext &base_instance_context);
357 
364  GatherTasksInfo &gather_info,
365  const InstancesComponent &instances_component,
366  const OrderedAttributes &ordered_attributes)
367 {
368  Vector<std::pair<int, GSpan>> attributes_to_override;
369  const CustomDataAttributes &attributes = instances_component.instance_attributes();
370  attributes.foreach_attribute(
371  [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
372  const int attribute_index = ordered_attributes.ids.index_of_try(attribute_id);
373  if (attribute_index == -1) {
374  /* The attribute is not propagated to the final geometry. */
375  return true;
376  }
377  GSpan span = *attributes.get_for_read(attribute_id);
378  const eCustomDataType expected_type = ordered_attributes.kinds[attribute_index].data_type;
379  if (meta_data.data_type != expected_type) {
380  const CPPType &from_type = span.type();
381  const CPPType &to_type = *custom_data_type_to_cpp_type(expected_type);
382  const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions();
383  if (!conversions.is_convertible(from_type, to_type)) {
384  /* Ignore the attribute because it can not be converted to the desired type. */
385  return true;
386  }
387  /* Convert the attribute on the instances component to the expected attribute type. */
388  std::unique_ptr<GArray<>> temporary_array = std::make_unique<GArray<>>(
389  to_type, instances_component.instances_num());
390  conversions.convert_to_initialized_n(span, temporary_array->as_mutable_span());
391  span = temporary_array->as_span();
392  gather_info.r_temporary_arrays.append(std::move(temporary_array));
393  }
394  attributes_to_override.append({attribute_index, span});
395  return true;
396  },
398  return attributes_to_override;
399 }
400 
406  const InstanceReference &reference,
407  const float4x4 &base_transform,
408  const uint32_t id,
409  FunctionRef<void(const GeometrySet &geometry_set, const float4x4 &transform, uint32_t id)> fn)
410 {
411  switch (reference.type()) {
413  const Object &object = reference.object();
414  const GeometrySet object_geometry_set = object_get_evaluated_geometry_set(object);
415  fn(object_geometry_set, base_transform, id);
416  break;
417  }
419  Collection &collection = reference.collection();
420  float4x4 offset_matrix = float4x4::identity();
421  sub_v3_v3(offset_matrix.values[3], collection.instance_offset);
422  int index = 0;
423  FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (&collection, object) {
424  const GeometrySet object_geometry_set = object_get_evaluated_geometry_set(*object);
425  const float4x4 matrix = base_transform * offset_matrix * object->obmat;
426  const int sub_id = noise::hash(id, index);
427  fn(object_geometry_set, matrix, sub_id);
428  index++;
429  }
431  break;
432  }
434  const GeometrySet &instance_geometry_set = reference.geometry_set();
435  fn(instance_geometry_set, base_transform, id);
436  break;
437  }
439  break;
440  }
441  }
442 }
443 
445  const InstancesComponent &instances_component,
446  const float4x4 &base_transform,
447  const InstanceContext &base_instance_context)
448 {
449  const Span<InstanceReference> references = instances_component.references();
450  const Span<int> handles = instances_component.instance_reference_handles();
451  const Span<float4x4> transforms = instances_component.instance_transforms();
452 
453  Span<int> stored_instance_ids;
454  if (gather_info.create_id_attribute_on_any_component) {
455  std::optional<GSpan> ids = instances_component.instance_attributes().get_for_read("id");
456  if (ids.has_value()) {
457  stored_instance_ids = ids->typed<int>();
458  }
459  }
460 
461  /* Prepare attribute fallbacks. */
462  InstanceContext instance_context = base_instance_context;
463  Vector<std::pair<int, GSpan>> pointcloud_attributes_to_override = prepare_attribute_fallbacks(
464  gather_info, instances_component, gather_info.pointclouds.attributes);
465  Vector<std::pair<int, GSpan>> mesh_attributes_to_override = prepare_attribute_fallbacks(
466  gather_info, instances_component, gather_info.meshes.attributes);
467  Vector<std::pair<int, GSpan>> curve_attributes_to_override = prepare_attribute_fallbacks(
468  gather_info, instances_component, gather_info.curves.attributes);
469 
470  for (const int i : transforms.index_range()) {
471  const int handle = handles[i];
472  const float4x4 &transform = transforms[i];
473  const InstanceReference &reference = references[handle];
474  const float4x4 new_base_transform = base_transform * transform;
475 
476  /* Update attribute fallbacks for the current instance. */
477  for (const std::pair<int, GSpan> &pair : pointcloud_attributes_to_override) {
478  instance_context.pointclouds.array[pair.first] = pair.second[i];
479  }
480  for (const std::pair<int, GSpan> &pair : mesh_attributes_to_override) {
481  instance_context.meshes.array[pair.first] = pair.second[i];
482  }
483  for (const std::pair<int, GSpan> &pair : curve_attributes_to_override) {
484  instance_context.curves.array[pair.first] = pair.second[i];
485  }
486 
487  uint32_t local_instance_id = 0;
488  if (gather_info.create_id_attribute_on_any_component) {
489  if (stored_instance_ids.is_empty()) {
490  local_instance_id = (uint32_t)i;
491  }
492  else {
493  local_instance_id = (uint32_t)stored_instance_ids[i];
494  }
495  }
496  const uint32_t instance_id = noise::hash(base_instance_context.id, local_instance_id);
497 
498  /* Add realize tasks for all referenced geometry sets recursively. */
500  new_base_transform,
501  instance_id,
502  [&](const GeometrySet &instance_geometry_set,
503  const float4x4 &transform,
504  const uint32_t id) {
505  instance_context.id = id;
506  gather_realize_tasks_recursive(gather_info,
507  instance_geometry_set,
508  transform,
509  instance_context);
510  });
511  }
512 }
513 
518  const GeometrySet &geometry_set,
519  const float4x4 &base_transform,
520  const InstanceContext &base_instance_context)
521 {
522  for (const GeometryComponent *component : geometry_set.get_components_for_read()) {
523  const GeometryComponentType type = component->type();
524  switch (type) {
526  const MeshComponent &mesh_component = *static_cast<const MeshComponent *>(component);
527  const Mesh *mesh = mesh_component.get_for_read();
528  if (mesh != nullptr && mesh->totvert > 0) {
529  const int mesh_index = gather_info.meshes.order.index_of(mesh);
530  const MeshRealizeInfo &mesh_info = gather_info.meshes.realize_info[mesh_index];
531  gather_info.r_tasks.mesh_tasks.append({gather_info.r_offsets.mesh_offsets,
532  &mesh_info,
533  base_transform,
534  base_instance_context.meshes,
535  base_instance_context.id});
536  gather_info.r_offsets.mesh_offsets.vertex += mesh->totvert;
537  gather_info.r_offsets.mesh_offsets.edge += mesh->totedge;
538  gather_info.r_offsets.mesh_offsets.loop += mesh->totloop;
539  gather_info.r_offsets.mesh_offsets.poly += mesh->totpoly;
540  }
541  break;
542  }
544  const PointCloudComponent &pointcloud_component =
545  *static_cast<const PointCloudComponent *>(component);
546  const PointCloud *pointcloud = pointcloud_component.get_for_read();
547  if (pointcloud != nullptr && pointcloud->totpoint > 0) {
548  const int pointcloud_index = gather_info.pointclouds.order.index_of(pointcloud);
549  const PointCloudRealizeInfo &pointcloud_info =
550  gather_info.pointclouds.realize_info[pointcloud_index];
551  gather_info.r_tasks.pointcloud_tasks.append({gather_info.r_offsets.pointcloud_offset,
552  &pointcloud_info,
553  base_transform,
554  base_instance_context.pointclouds,
555  base_instance_context.id});
556  gather_info.r_offsets.pointcloud_offset += pointcloud->totpoint;
557  }
558  break;
559  }
561  const CurveComponent &curve_component = *static_cast<const CurveComponent *>(component);
562  const Curves *curves = curve_component.get_for_read();
563  if (curves != nullptr && curves->geometry.curve_num > 0) {
564  const int curve_index = gather_info.curves.order.index_of(curves);
565  const RealizeCurveInfo &curve_info = gather_info.curves.realize_info[curve_index];
566  gather_info.r_tasks.curve_tasks.append({gather_info.r_offsets.curves_offsets,
567  &curve_info,
568  base_transform,
569  base_instance_context.curves,
570  base_instance_context.id});
571  gather_info.r_offsets.curves_offsets.point += curves->geometry.point_num;
572  gather_info.r_offsets.curves_offsets.curve += curves->geometry.curve_num;
573  }
574  break;
575  }
577  const InstancesComponent &instances_component = *static_cast<const InstancesComponent *>(
578  component);
580  gather_info, instances_component, base_transform, base_instance_context);
581  break;
582  }
584  const VolumeComponent *volume_component = static_cast<const VolumeComponent *>(component);
585  if (!gather_info.r_tasks.first_volume) {
586  volume_component->user_add();
587  gather_info.r_tasks.first_volume = volume_component;
588  }
589  break;
590  }
592  const GeometryComponentEditData *edit_component =
593  static_cast<const GeometryComponentEditData *>(component);
594  if (!gather_info.r_tasks.first_edit_data) {
595  edit_component->user_add();
596  gather_info.r_tasks.first_edit_data = edit_component;
597  }
598  break;
599  }
600  }
601  }
602 }
603 
606 /* -------------------------------------------------------------------- */
611  const GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, bool &r_create_id)
612 {
613  Vector<GeometryComponentType> src_component_types;
614  src_component_types.append(GEO_COMPONENT_TYPE_POINT_CLOUD);
615  if (options.realize_instance_attributes) {
616  src_component_types.append(GEO_COMPONENT_TYPE_INSTANCES);
617  }
618 
619  Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
620  in_geometry_set.gather_attributes_for_propagation(
621  src_component_types, GEO_COMPONENT_TYPE_POINT_CLOUD, true, attributes_to_propagate);
622  attributes_to_propagate.remove("position");
623  r_create_id = attributes_to_propagate.pop_try("id").has_value();
624  OrderedAttributes ordered_attributes;
625  for (const auto item : attributes_to_propagate.items()) {
626  ordered_attributes.ids.add_new(item.key);
627  ordered_attributes.kinds.append(item.value);
628  }
629  return ordered_attributes;
630 }
631 
632 static void gather_pointclouds_to_realize(const GeometrySet &geometry_set,
633  VectorSet<const PointCloud *> &r_pointclouds)
634 {
635  if (const PointCloud *pointcloud = geometry_set.get_pointcloud_for_read()) {
636  if (pointcloud->totpoint > 0) {
637  r_pointclouds.add(pointcloud);
638  }
639  }
640  if (const InstancesComponent *instances =
641  geometry_set.get_component_for_read<InstancesComponent>()) {
642  instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
643  gather_pointclouds_to_realize(instance_geometry_set, r_pointclouds);
644  });
645  }
646 }
647 
650 {
651  AllPointCloudsInfo info;
653  geometry_set, options, info.create_id_attribute);
654 
655  gather_pointclouds_to_realize(geometry_set, info.order);
656  info.realize_info.reinitialize(info.order.size());
657  for (const int pointcloud_index : info.realize_info.index_range()) {
658  PointCloudRealizeInfo &pointcloud_info = info.realize_info[pointcloud_index];
659  const PointCloud *pointcloud = info.order[pointcloud_index];
660  pointcloud_info.pointcloud = pointcloud;
661 
662  /* Access attributes. */
663  bke::AttributeAccessor attributes = bke::pointcloud_attributes(*pointcloud);
664  pointcloud_info.attributes.reinitialize(info.attributes.size());
665  for (const int attribute_index : info.attributes.index_range()) {
666  const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index];
667  const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
668  const eAttrDomain domain = info.attributes.kinds[attribute_index].domain;
669  if (attributes.contains(attribute_id)) {
670  GVArray attribute = attributes.lookup_or_default(attribute_id, domain, data_type);
671  pointcloud_info.attributes[attribute_index].emplace(std::move(attribute));
672  }
673  }
674  if (info.create_id_attribute) {
675  bke::GAttributeReader ids_attribute = attributes.lookup("id");
676  if (ids_attribute) {
677  pointcloud_info.stored_ids = ids_attribute.varray.get_internal_span().typed<int>();
678  }
679  }
680  const VArray<float3> position_attribute = attributes.lookup_or_default<float3>(
681  "position", ATTR_DOMAIN_POINT, float3(0));
682  pointcloud_info.positions = position_attribute.get_internal_span();
683  }
684  return info;
685 }
686 
690  const OrderedAttributes &ordered_attributes,
691  MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
692  MutableSpan<int> all_dst_ids,
693  MutableSpan<float3> all_dst_positions)
694 {
695  const PointCloudRealizeInfo &pointcloud_info = *task.pointcloud_info;
696  const PointCloud &pointcloud = *pointcloud_info.pointcloud;
697  const IndexRange point_slice{task.start_index, pointcloud.totpoint};
698 
700  pointcloud_info.positions, task.transform, all_dst_positions.slice(point_slice));
701 
702  /* Create point ids. */
703  if (!all_dst_ids.is_empty()) {
705  options, pointcloud_info.stored_ids, task.id, all_dst_ids.slice(point_slice));
706  }
707 
709  pointcloud_info.attributes,
710  task.attribute_fallbacks,
711  ordered_attributes,
712  [&](const eAttrDomain domain) {
713  BLI_assert(domain == ATTR_DOMAIN_POINT);
714  UNUSED_VARS_NDEBUG(domain);
715  return point_slice;
716  },
717  dst_attribute_writers);
718 }
719 
721  const AllPointCloudsInfo &all_pointclouds_info,
722  const Span<RealizePointCloudTask> tasks,
723  const OrderedAttributes &ordered_attributes,
724  GeometrySet &r_realized_geometry)
725 {
726  if (tasks.is_empty()) {
727  return;
728  }
729 
730  const RealizePointCloudTask &last_task = tasks.last();
731  const PointCloud &last_pointcloud = *last_task.pointcloud_info->pointcloud;
732  const int tot_points = last_task.start_index + last_pointcloud.totpoint;
733 
734  /* Allocate new point cloud. */
735  PointCloud *dst_pointcloud = BKE_pointcloud_new_nomain(tot_points);
736  PointCloudComponent &dst_component =
737  r_realized_geometry.get_component_for_write<PointCloudComponent>();
738  dst_component.replace(dst_pointcloud);
740  *dst_pointcloud);
741 
743  "position", ATTR_DOMAIN_POINT);
744 
745  /* Prepare id attribute. */
746  SpanAttributeWriter<int> point_ids;
747  if (all_pointclouds_info.create_id_attribute) {
748  point_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id", ATTR_DOMAIN_POINT);
749  }
750 
751  /* Prepare generic output attributes. */
752  Vector<GSpanAttributeWriter> dst_attribute_writers;
753  for (const int attribute_index : ordered_attributes.index_range()) {
754  const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
755  const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
756  dst_attribute_writers.append(dst_attributes.lookup_or_add_for_write_only_span(
757  attribute_id, ATTR_DOMAIN_POINT, data_type));
758  }
759 
760  /* Actually execute all tasks. */
761  threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
762  for (const int task_index : task_range) {
763  const RealizePointCloudTask &task = tasks[task_index];
764  execute_realize_pointcloud_task(options,
765  task,
766  ordered_attributes,
767  dst_attribute_writers,
768  point_ids.span,
769  positions.span);
770  }
771  });
772 
773  /* Tag modified attributes. */
774  for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
775  dst_attribute.finish();
776  }
777  positions.finish();
778  if (point_ids) {
779  point_ids.finish();
780  }
781 }
782 
785 /* -------------------------------------------------------------------- */
790  const GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, bool &r_create_id)
791 {
792  Vector<GeometryComponentType> src_component_types;
793  src_component_types.append(GEO_COMPONENT_TYPE_MESH);
794  if (options.realize_instance_attributes) {
795  src_component_types.append(GEO_COMPONENT_TYPE_INSTANCES);
796  }
797 
798  Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
799  in_geometry_set.gather_attributes_for_propagation(
800  src_component_types, GEO_COMPONENT_TYPE_MESH, true, attributes_to_propagate);
801  attributes_to_propagate.remove("position");
802  attributes_to_propagate.remove("normal");
803  attributes_to_propagate.remove("material_index");
804  attributes_to_propagate.remove("shade_smooth");
805  attributes_to_propagate.remove("crease");
806  r_create_id = attributes_to_propagate.pop_try("id").has_value();
807  OrderedAttributes ordered_attributes;
808  for (const auto item : attributes_to_propagate.items()) {
809  ordered_attributes.ids.add_new(item.key);
810  ordered_attributes.kinds.append(item.value);
811  }
812  return ordered_attributes;
813 }
814 
815 static void gather_meshes_to_realize(const GeometrySet &geometry_set,
816  VectorSet<const Mesh *> &r_meshes)
817 {
818  if (const Mesh *mesh = geometry_set.get_mesh_for_read()) {
819  if (mesh->totvert > 0) {
820  r_meshes.add(mesh);
821  }
822  }
823  if (const InstancesComponent *instances =
824  geometry_set.get_component_for_read<InstancesComponent>()) {
825  instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
826  gather_meshes_to_realize(instance_geometry_set, r_meshes);
827  });
828  }
829 }
830 
831 static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set,
833 {
834  AllMeshesInfo info;
836  geometry_set, options, info.create_id_attribute);
837 
838  gather_meshes_to_realize(geometry_set, info.order);
839  for (const Mesh *mesh : info.order) {
840  for (const int slot_index : IndexRange(mesh->totcol)) {
841  Material *material = mesh->mat[slot_index];
842  info.materials.add(material);
843  }
844  }
845  info.realize_info.reinitialize(info.order.size());
846  for (const int mesh_index : info.realize_info.index_range()) {
847  MeshRealizeInfo &mesh_info = info.realize_info[mesh_index];
848  const Mesh *mesh = info.order[mesh_index];
849  mesh_info.mesh = mesh;
850 
851  /* Create material index mapping. */
853  for (const int old_slot_index : IndexRange(mesh->totcol)) {
854  Material *material = mesh->mat[old_slot_index];
855  const int new_slot_index = info.materials.index_of(material);
856  mesh_info.material_index_map[old_slot_index] = new_slot_index;
857  }
858 
859  /* Access attributes. */
861  mesh_info.attributes.reinitialize(info.attributes.size());
862  for (const int attribute_index : info.attributes.index_range()) {
863  const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index];
864  const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
865  const eAttrDomain domain = info.attributes.kinds[attribute_index].domain;
866  if (attributes.contains(attribute_id)) {
867  GVArray attribute = attributes.lookup_or_default(attribute_id, domain, data_type);
868  mesh_info.attributes[attribute_index].emplace(std::move(attribute));
869  }
870  }
871  if (info.create_id_attribute) {
872  bke::GAttributeReader ids_attribute = attributes.lookup("id");
873  if (ids_attribute) {
874  mesh_info.stored_vertex_ids = ids_attribute.varray.get_internal_span().typed<int>();
875  }
876  }
877  }
878  return info;
879 }
880 
882  const RealizeMeshTask &task,
883  const OrderedAttributes &ordered_attributes,
884  Mesh &dst_mesh,
885  MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
886  MutableSpan<int> all_dst_vertex_ids)
887 {
888  const MeshRealizeInfo &mesh_info = *task.mesh_info;
889  const Mesh &mesh = *mesh_info.mesh;
890 
891  const Span<MVert> src_verts{mesh.mvert, mesh.totvert};
892  const Span<MEdge> src_edges{mesh.medge, mesh.totedge};
893  const Span<MLoop> src_loops{mesh.mloop, mesh.totloop};
894  const Span<MPoly> src_polys{mesh.mpoly, mesh.totpoly};
895 
896  MutableSpan<MVert> dst_verts{dst_mesh.mvert + task.start_indices.vertex, mesh.totvert};
897  MutableSpan<MEdge> dst_edges{dst_mesh.medge + task.start_indices.edge, mesh.totedge};
898  MutableSpan<MLoop> dst_loops{dst_mesh.mloop + task.start_indices.loop, mesh.totloop};
899  MutableSpan<MPoly> dst_polys{dst_mesh.mpoly + task.start_indices.poly, mesh.totpoly};
900 
901  const Span<int> material_index_map = mesh_info.material_index_map;
902 
903  threading::parallel_for(IndexRange(mesh.totvert), 1024, [&](const IndexRange vert_range) {
904  for (const int i : vert_range) {
905  const MVert &src_vert = src_verts[i];
906  MVert &dst_vert = dst_verts[i];
907  dst_vert = src_vert;
908  copy_v3_v3(dst_vert.co, task.transform * float3(src_vert.co));
909  }
910  });
911  threading::parallel_for(IndexRange(mesh.totedge), 1024, [&](const IndexRange edge_range) {
912  for (const int i : edge_range) {
913  const MEdge &src_edge = src_edges[i];
914  MEdge &dst_edge = dst_edges[i];
915  dst_edge = src_edge;
916  dst_edge.v1 += task.start_indices.vertex;
917  dst_edge.v2 += task.start_indices.vertex;
918  }
919  });
920  threading::parallel_for(IndexRange(mesh.totloop), 1024, [&](const IndexRange loop_range) {
921  for (const int i : loop_range) {
922  const MLoop &src_loop = src_loops[i];
923  MLoop &dst_loop = dst_loops[i];
924  dst_loop = src_loop;
925  dst_loop.v += task.start_indices.vertex;
926  dst_loop.e += task.start_indices.edge;
927  }
928  });
929  threading::parallel_for(IndexRange(mesh.totpoly), 1024, [&](const IndexRange poly_range) {
930  for (const int i : poly_range) {
931  const MPoly &src_poly = src_polys[i];
932  MPoly &dst_poly = dst_polys[i];
933  dst_poly = src_poly;
934  dst_poly.loopstart += task.start_indices.loop;
935  if (src_poly.mat_nr >= 0 && src_poly.mat_nr < mesh.totcol) {
936  dst_poly.mat_nr = material_index_map[src_poly.mat_nr];
937  }
938  else {
939  /* The material index was invalid before. */
940  dst_poly.mat_nr = 0;
941  }
942  }
943  });
944 
945  if (!all_dst_vertex_ids.is_empty()) {
947  mesh_info.stored_vertex_ids,
948  task.id,
949  all_dst_vertex_ids.slice(task.start_indices.vertex, mesh.totvert));
950  }
951 
953  mesh_info.attributes,
954  task.attribute_fallbacks,
955  ordered_attributes,
956  [&](const eAttrDomain domain) {
957  switch (domain) {
958  case ATTR_DOMAIN_POINT:
959  return IndexRange(task.start_indices.vertex, mesh.totvert);
960  case ATTR_DOMAIN_EDGE:
961  return IndexRange(task.start_indices.edge, mesh.totedge);
962  case ATTR_DOMAIN_CORNER:
963  return IndexRange(task.start_indices.loop, mesh.totloop);
964  case ATTR_DOMAIN_FACE:
965  return IndexRange(task.start_indices.poly, mesh.totpoly);
966  default:
967  BLI_assert_unreachable();
968  return IndexRange();
969  }
970  },
971  dst_attribute_writers);
972 }
973 
975  const AllMeshesInfo &all_meshes_info,
976  const Span<RealizeMeshTask> tasks,
977  const OrderedAttributes &ordered_attributes,
978  const VectorSet<Material *> &ordered_materials,
979  GeometrySet &r_realized_geometry)
980 {
981  if (tasks.is_empty()) {
982  return;
983  }
984 
985  const RealizeMeshTask &last_task = tasks.last();
986  const Mesh &last_mesh = *last_task.mesh_info->mesh;
987  const int tot_vertices = last_task.start_indices.vertex + last_mesh.totvert;
988  const int tot_edges = last_task.start_indices.edge + last_mesh.totedge;
989  const int tot_loops = last_task.start_indices.loop + last_mesh.totloop;
990  const int tot_poly = last_task.start_indices.poly + last_mesh.totpoly;
991 
992  Mesh *dst_mesh = BKE_mesh_new_nomain(tot_vertices, tot_edges, 0, tot_loops, tot_poly);
993  MeshComponent &dst_component = r_realized_geometry.get_component_for_write<MeshComponent>();
994  dst_component.replace(dst_mesh);
996 
997  /* Copy settings from the first input geometry set with a mesh. */
998  const RealizeMeshTask &first_task = tasks.first();
999  const Mesh &first_mesh = *first_task.mesh_info->mesh;
1000  BKE_mesh_copy_parameters_for_eval(dst_mesh, &first_mesh);
1001  /* The above line also copies vertex group names. We don't want that here because the new
1002  * attributes are added explicitly below. */
1003  BLI_freelistN(&dst_mesh->vertex_group_names);
1004 
1005  /* Add materials. */
1006  for (const int i : IndexRange(ordered_materials.size())) {
1007  Material *material = ordered_materials[i];
1008  BKE_id_material_eval_assign(&dst_mesh->id, i + 1, material);
1009  }
1010 
1011  /* Prepare id attribute. */
1012  SpanAttributeWriter<int> vertex_ids;
1013  if (all_meshes_info.create_id_attribute) {
1014  vertex_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id", ATTR_DOMAIN_POINT);
1015  }
1016 
1017  /* Prepare generic output attributes. */
1018  Vector<GSpanAttributeWriter> dst_attribute_writers;
1019  for (const int attribute_index : ordered_attributes.index_range()) {
1020  const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
1021  const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
1022  const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
1023  dst_attribute_writers.append(
1024  dst_attributes.lookup_or_add_for_write_only_span(attribute_id, domain, data_type));
1025  }
1026 
1027  /* Actually execute all tasks. */
1028  threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
1029  for (const int task_index : task_range) {
1030  const RealizeMeshTask &task = tasks[task_index];
1031  execute_realize_mesh_task(
1032  options, task, ordered_attributes, *dst_mesh, dst_attribute_writers, vertex_ids.span);
1033  }
1034  });
1035 
1036  /* Tag modified attributes. */
1037  for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
1038  dst_attribute.finish();
1039  }
1040  if (vertex_ids) {
1041  vertex_ids.finish();
1042  }
1043 }
1044 
1047 /* -------------------------------------------------------------------- */
1052  const GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, bool &r_create_id)
1053 {
1054  Vector<GeometryComponentType> src_component_types;
1055  src_component_types.append(GEO_COMPONENT_TYPE_CURVE);
1056  if (options.realize_instance_attributes) {
1057  src_component_types.append(GEO_COMPONENT_TYPE_INSTANCES);
1058  }
1059 
1060  Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
1061  in_geometry_set.gather_attributes_for_propagation(
1062  src_component_types, GEO_COMPONENT_TYPE_CURVE, true, attributes_to_propagate);
1063  attributes_to_propagate.remove("position");
1064  attributes_to_propagate.remove("radius");
1065  attributes_to_propagate.remove("resolution");
1066  attributes_to_propagate.remove("handle_right");
1067  attributes_to_propagate.remove("handle_left");
1068  r_create_id = attributes_to_propagate.pop_try("id").has_value();
1069  OrderedAttributes ordered_attributes;
1070  for (const auto item : attributes_to_propagate.items()) {
1071  ordered_attributes.ids.add_new(item.key);
1072  ordered_attributes.kinds.append(item.value);
1073  }
1074  return ordered_attributes;
1075 }
1076 
1077 static void gather_curves_to_realize(const GeometrySet &geometry_set,
1078  VectorSet<const Curves *> &r_curves)
1079 {
1080  if (const Curves *curves = geometry_set.get_curves_for_read()) {
1081  if (curves->geometry.curve_num != 0) {
1082  r_curves.add(curves);
1083  }
1084  }
1085  if (const InstancesComponent *instances =
1086  geometry_set.get_component_for_read<InstancesComponent>()) {
1087  instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
1088  gather_curves_to_realize(instance_geometry_set, r_curves);
1089  });
1090  }
1091 }
1092 
1093 static AllCurvesInfo preprocess_curves(const GeometrySet &geometry_set,
1095 {
1096  AllCurvesInfo info;
1098  geometry_set, options, info.create_id_attribute);
1099 
1100  gather_curves_to_realize(geometry_set, info.order);
1101  info.realize_info.reinitialize(info.order.size());
1102  for (const int curve_index : info.realize_info.index_range()) {
1103  RealizeCurveInfo &curve_info = info.realize_info[curve_index];
1104  const Curves *curves_id = info.order[curve_index];
1106  curve_info.curves = curves_id;
1107 
1108  /* Access attributes. */
1109  bke::AttributeAccessor attributes = curves.attributes();
1110  curve_info.attributes.reinitialize(info.attributes.size());
1111  for (const int attribute_index : info.attributes.index_range()) {
1112  const eAttrDomain domain = info.attributes.kinds[attribute_index].domain;
1113  const AttributeIDRef &attribute_id = info.attributes.ids[attribute_index];
1114  const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
1115  if (attributes.contains(attribute_id)) {
1116  GVArray attribute = attributes.lookup_or_default(attribute_id, domain, data_type);
1117  curve_info.attributes[attribute_index].emplace(std::move(attribute));
1118  }
1119  }
1120  if (info.create_id_attribute) {
1121  bke::GAttributeReader id_attribute = attributes.lookup("id");
1122  if (id_attribute) {
1123  curve_info.stored_ids = id_attribute.varray.get_internal_span().typed<int>();
1124  }
1125  }
1126 
1127  /* Retrieve the radius attribute, if it exists. */
1128  if (attributes.contains("radius")) {
1129  curve_info.radius =
1130  attributes.lookup<float>("radius", ATTR_DOMAIN_POINT).get_internal_span();
1131  info.create_radius_attribute = true;
1132  }
1133 
1134  /* Retrieve the resolution attribute, if it exists. */
1135  curve_info.resolution = curves.resolution();
1136  if (attributes.contains("resolution")) {
1137  info.create_resolution_attribute = true;
1138  }
1139 
1140  /* Retrieve handle position attributes, if they exist. */
1141  if (attributes.contains("handle_right")) {
1142  curve_info.handle_left =
1143  attributes.lookup<float3>("handle_left", ATTR_DOMAIN_POINT).get_internal_span();
1144  curve_info.handle_right =
1145  attributes.lookup<float3>("handle_right", ATTR_DOMAIN_POINT).get_internal_span();
1147  }
1148  }
1149  return info;
1150 }
1151 
1153  const AllCurvesInfo &all_curves_info,
1154  const RealizeCurveTask &task,
1155  const OrderedAttributes &ordered_attributes,
1156  bke::CurvesGeometry &dst_curves,
1157  MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
1158  MutableSpan<int> all_dst_ids,
1159  MutableSpan<float3> all_handle_left,
1160  MutableSpan<float3> all_handle_right,
1161  MutableSpan<float> all_radii,
1162  MutableSpan<int> all_resolutions)
1163 {
1164  const RealizeCurveInfo &curves_info = *task.curve_info;
1165  const Curves &curves_id = *curves_info.curves;
1167 
1168  const IndexRange dst_point_range{task.start_indices.point, curves.points_num()};
1169  const IndexRange dst_curve_range{task.start_indices.curve, curves.curves_num()};
1170 
1172  curves.positions(), task.transform, dst_curves.positions_for_write().slice(dst_point_range));
1173 
1174  /* Copy and transform handle positions if necessary. */
1175  if (all_curves_info.create_handle_postion_attributes) {
1176  if (curves_info.handle_left.is_empty()) {
1177  all_handle_left.slice(dst_point_range).fill(float3(0));
1178  }
1179  else {
1181  curves_info.handle_left, task.transform, all_handle_left.slice(dst_point_range));
1182  }
1183  if (curves_info.handle_right.is_empty()) {
1184  all_handle_right.slice(dst_point_range).fill(float3(0));
1185  }
1186  else {
1188  curves_info.handle_right, task.transform, all_handle_right.slice(dst_point_range));
1189  }
1190  }
1191 
1192  /* Copy radius attribute with 1.0 default if it doesn't exist. */
1193  if (all_curves_info.create_radius_attribute) {
1194  if (curves_info.radius.is_empty()) {
1195  all_radii.slice(dst_point_range).fill(1.0f);
1196  }
1197  else {
1198  all_radii.slice(dst_point_range).copy_from(curves_info.radius);
1199  }
1200  }
1201 
1202  if (all_curves_info.create_resolution_attribute) {
1203  curves_info.resolution.materialize(all_resolutions.slice(dst_curve_range));
1204  }
1205 
1206  /* Copy curve offsets. */
1207  const Span<int> src_offsets = curves.offsets();
1208  const MutableSpan<int> dst_offsets = dst_curves.offsets_for_write().slice(dst_curve_range);
1209  threading::parallel_for(curves.curves_range(), 2048, [&](const IndexRange range) {
1210  for (const int i : range) {
1211  dst_offsets[i] = task.start_indices.point + src_offsets[i];
1212  }
1213  });
1214 
1215  if (!all_dst_ids.is_empty()) {
1217  options, curves_info.stored_ids, task.id, all_dst_ids.slice(dst_point_range));
1218  }
1219 
1221  curves_info.attributes,
1222  task.attribute_fallbacks,
1223  ordered_attributes,
1224  [&](const eAttrDomain domain) {
1225  switch (domain) {
1226  case ATTR_DOMAIN_POINT:
1227  return IndexRange(task.start_indices.point, curves.points_num());
1228  case ATTR_DOMAIN_CURVE:
1229  return IndexRange(task.start_indices.curve, curves.curves_num());
1230  default:
1231  BLI_assert_unreachable();
1232  return IndexRange();
1233  }
1234  },
1235  dst_attribute_writers);
1236 }
1237 
1239  const AllCurvesInfo &all_curves_info,
1240  const Span<RealizeCurveTask> tasks,
1241  const OrderedAttributes &ordered_attributes,
1242  GeometrySet &r_realized_geometry)
1243 {
1244  if (tasks.is_empty()) {
1245  return;
1246  }
1247 
1248  const RealizeCurveTask &last_task = tasks.last();
1249  const Curves &last_curves = *last_task.curve_info->curves;
1250  const int points_num = last_task.start_indices.point + last_curves.geometry.point_num;
1251  const int curves_num = last_task.start_indices.curve + last_curves.geometry.curve_num;
1252 
1253  /* Allocate new curves data-block. */
1254  Curves *dst_curves_id = bke::curves_new_nomain(points_num, curves_num);
1255  bke::CurvesGeometry &dst_curves = bke::CurvesGeometry::wrap(dst_curves_id->geometry);
1256  dst_curves.offsets_for_write().last() = points_num;
1257  CurveComponent &dst_component = r_realized_geometry.get_component_for_write<CurveComponent>();
1258  dst_component.replace(dst_curves_id);
1259  bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
1260 
1261  /* Copy settings from the first input geometry set with curves. */
1262  const RealizeCurveTask &first_task = tasks.first();
1263  const Curves &first_curves_id = *first_task.curve_info->curves;
1264  bke::curves_copy_parameters(first_curves_id, *dst_curves_id);
1265 
1266  /* Prepare id attribute. */
1267  SpanAttributeWriter<int> point_ids;
1268  if (all_curves_info.create_id_attribute) {
1269  point_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id", ATTR_DOMAIN_POINT);
1270  }
1271 
1272  /* Prepare generic output attributes. */
1273  Vector<GSpanAttributeWriter> dst_attribute_writers;
1274  for (const int attribute_index : ordered_attributes.index_range()) {
1275  const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
1276  const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
1277  const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
1278  dst_attribute_writers.append(
1279  dst_attributes.lookup_or_add_for_write_only_span(attribute_id, domain, data_type));
1280  }
1281 
1282  /* Prepare handle position attributes if necessary. */
1283  SpanAttributeWriter<float3> handle_left;
1284  SpanAttributeWriter<float3> handle_right;
1285  if (all_curves_info.create_handle_postion_attributes) {
1286  handle_left = dst_attributes.lookup_or_add_for_write_only_span<float3>("handle_left",
1288  handle_right = dst_attributes.lookup_or_add_for_write_only_span<float3>("handle_right",
1290  }
1291 
1292  /* Prepare radius attribute if necessary. */
1294  if (all_curves_info.create_radius_attribute) {
1295  radius = dst_attributes.lookup_or_add_for_write_only_span<float>("radius", ATTR_DOMAIN_POINT);
1296  }
1297 
1298  /* Prepare resolution attribute if necessary. */
1299  SpanAttributeWriter<int> resolution;
1300  if (all_curves_info.create_resolution_attribute) {
1301  resolution = dst_attributes.lookup_or_add_for_write_only_span<int>("resolution",
1303  }
1304 
1305  /* Actually execute all tasks. */
1306  threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
1307  for (const int task_index : task_range) {
1308  const RealizeCurveTask &task = tasks[task_index];
1309  execute_realize_curve_task(options,
1310  all_curves_info,
1311  task,
1312  ordered_attributes,
1313  dst_curves,
1314  dst_attribute_writers,
1315  point_ids.span,
1316  handle_left.span,
1317  handle_right.span,
1318  radius.span,
1319  resolution.span);
1320  }
1321  });
1322 
1323  /* Type counts have to be updated eagerly. */
1324  dst_curves.runtime->type_counts.fill(0);
1325  for (const RealizeCurveTask &task : tasks) {
1326  for (const int i : IndexRange(CURVE_TYPES_NUM)) {
1327  dst_curves.runtime->type_counts[i] +=
1328  task.curve_info->curves->geometry.runtime->type_counts[i];
1329  }
1330  }
1331 
1332  /* Tag modified attributes. */
1333  for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
1334  dst_attribute.finish();
1335  }
1336  if (point_ids) {
1337  point_ids.finish();
1338  }
1339  if (radius) {
1340  radius.finish();
1341  }
1342  if (resolution) {
1343  resolution.finish();
1344  }
1345  if (all_curves_info.create_handle_postion_attributes) {
1346  handle_left.finish();
1347  handle_right.finish();
1348  }
1349 }
1350 
1353 /* -------------------------------------------------------------------- */
1358 {
1359  geometry_set.modify_geometry_sets([&](GeometrySet &sub_geometry) {
1360  if (sub_geometry.has<InstancesComponent>()) {
1361  InstancesComponent &component = sub_geometry.get_component_for_write<InstancesComponent>();
1362  component.instance_attributes().remove("id");
1363  }
1364  });
1365 }
1366 
1368 {
1369  /* The algorithm works in three steps:
1370  * 1. Preprocess each unique geometry that is instanced (e.g. each `Mesh`).
1371  * 2. Gather "tasks" that need to be executed to realize the instances. Each task corresponds to
1372  * instances of the previously preprocessed geometry.
1373  * 3. Execute all tasks in parallel.
1374  */
1375 
1376  if (!geometry_set.has_instances()) {
1377  return geometry_set;
1378  }
1379 
1380  if (options.keep_original_ids) {
1381  remove_id_attribute_from_instances(geometry_set);
1382  }
1383 
1384  AllPointCloudsInfo all_pointclouds_info = preprocess_pointclouds(geometry_set, options);
1385  AllMeshesInfo all_meshes_info = preprocess_meshes(geometry_set, options);
1386  AllCurvesInfo all_curves_info = preprocess_curves(geometry_set, options);
1387 
1388  Vector<std::unique_ptr<GArray<>>> temporary_arrays;
1389  const bool create_id_attribute = all_pointclouds_info.create_id_attribute ||
1390  all_meshes_info.create_id_attribute ||
1391  all_curves_info.create_id_attribute;
1392  GatherTasksInfo gather_info = {all_pointclouds_info,
1393  all_meshes_info,
1394  all_curves_info,
1395  create_id_attribute,
1396  temporary_arrays};
1397  const float4x4 transform = float4x4::identity();
1398  InstanceContext attribute_fallbacks(gather_info);
1399  gather_realize_tasks_recursive(gather_info, geometry_set, transform, attribute_fallbacks);
1400 
1401  GeometrySet new_geometry_set;
1403  all_pointclouds_info,
1404  gather_info.r_tasks.pointcloud_tasks,
1405  all_pointclouds_info.attributes,
1406  new_geometry_set);
1408  all_meshes_info,
1409  gather_info.r_tasks.mesh_tasks,
1410  all_meshes_info.attributes,
1411  all_meshes_info.materials,
1412  new_geometry_set);
1414  all_curves_info,
1415  gather_info.r_tasks.curve_tasks,
1416  all_curves_info.attributes,
1417  new_geometry_set);
1418 
1419  if (gather_info.r_tasks.first_volume) {
1420  new_geometry_set.add(*gather_info.r_tasks.first_volume);
1421  }
1422  if (gather_info.r_tasks.first_edit_data) {
1423  new_geometry_set.add(*gather_info.r_tasks.first_edit_data);
1424  }
1425 
1426  return new_geometry_set;
1427 }
1428 
1431 } // namespace blender::geometry
eAttrDomain
Definition: BKE_attribute.h:25
@ ATTR_DOMAIN_CURVE
Definition: BKE_attribute.h:31
@ ATTR_DOMAIN_INSTANCE
Definition: BKE_attribute.h:32
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_END
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(_collection, _object)
Low-level operations for curves.
support for deformation groups and hooks.
GeometryComponentType
@ GEO_COMPONENT_TYPE_MESH
@ GEO_COMPONENT_TYPE_POINT_CLOUD
@ GEO_COMPONENT_TYPE_INSTANCES
@ GEO_COMPONENT_TYPE_EDIT
@ GEO_COMPONENT_TYPE_CURVE
@ GEO_COMPONENT_TYPE_VOLUME
General operations, lookup, etc. for materials.
void BKE_id_material_eval_assign(struct ID *id, int slot, struct Material *material)
Definition: material.c:758
void BKE_mesh_copy_parameters_for_eval(struct Mesh *me_dst, const struct Mesh *me_src)
struct Mesh * BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
Definition: mesh.cc:991
General operations for point clouds.
struct PointCloud * BKE_pointcloud_new_nomain(int totpoint)
Definition: pointcloud.cc:243
#define BLI_assert(a)
Definition: BLI_assert.h:46
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:466
MINLINE void sub_v3_v3(float r[3], const float a[3])
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:108
Object groups, one object can be in many groups at once.
#define CURVE_TYPES_NUM
eCustomDataType
Object is a sort of wrapper for general info.
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
float float4x4[4][4]
float float3[3]
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to curves
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
const Curves * get_for_read() const
void replace(Curves *curve, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
void user_add() const
Definition: geometry_set.cc:84
Object & object() const
Collection & collection() const
const GeometrySet & geometry_set() const
blender::Span< int > instance_reference_handles() const
blender::bke::CustomDataAttributes & instance_attributes()
blender::Span< InstanceReference > references() const
blender::MutableSpan< blender::float4x4 > instance_transforms()
const Mesh * get_for_read() const
void replace(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
void replace(PointCloud *pointcloud, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
const PointCloud * get_for_read() const
void reinitialize(const int64_t new_size)
Definition: BLI_array.hh:387
const CPPType & type() const
const CPPType * type() const
Span< T > typed() const
bool remove(const Key &key)
Definition: BLI_map.hh:323
ItemIterator items() const
Definition: BLI_map.hh:859
std::optional< Value > pop_try(const Key &key)
Definition: BLI_map.hh:374
constexpr void fill(const T &value)
Definition: BLI_span.hh:527
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition: BLI_span.hh:581
constexpr bool is_empty() const
Definition: BLI_span.hh:519
constexpr void copy_from(Span< T > values)
Definition: BLI_span.hh:707
constexpr IndexRange index_range() const
Definition: BLI_span.hh:661
constexpr const T & first() const
Definition: BLI_span.hh:303
constexpr const T & last(const int64_t n=0) const
Definition: BLI_span.hh:313
constexpr IndexRange index_range() const
Definition: BLI_span.hh:401
constexpr bool is_empty() const
Definition: BLI_span.hh:248
void materialize(MutableSpan< T > r_span) const
Span< T > get_internal_span() const
int64_t index_of(const Key &key) const
bool add(const Key &key)
int64_t size() const
int64_t size() const
Definition: BLI_vector.hh:694
void append(const T &value)
Definition: BLI_vector.hh:433
IndexRange index_range() const
Definition: BLI_vector.hh:920
bool contains(const AttributeIDRef &attribute_id) const
GAttributeReader lookup(const AttributeIDRef &attribute_id) const
GVArray lookup_or_default(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, const void *default_value=nullptr) const
MutableSpan< float3 > positions_for_write()
MutableAttributeAccessor attributes_for_write()
MutableSpan< int > offsets_for_write()
std::optional< blender::GSpan > get_for_read(const AttributeIDRef &attribute_id) const
bool foreach_attribute(const AttributeForeachCallback callback, eAttrDomain domain) const
GSpanAttributeWriter lookup_or_add_for_write_only_span(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type)
CCL_NAMESPACE_BEGIN struct Options options
Material material
SyclQueue void void * src
static struct PartialUpdateUser * wrap(PartialUpdateUserImpl *user)
const blender::CPPType * custom_data_type_to_cpp_type(const eCustomDataType type)
Definition: customdata.cc:5312
void curves_copy_parameters(const Curves &src, Curves &dst)
Definition: curves.cc:391
GeometrySet object_get_evaluated_geometry_set(const Object &object)
AttributeAccessor pointcloud_attributes(const PointCloud &pointcloud)
MutableAttributeAccessor pointcloud_attributes_for_write(PointCloud &pointcloud)
AttributeAccessor mesh_attributes(const Mesh &mesh)
MutableAttributeAccessor mesh_attributes_for_write(Mesh &mesh)
Curves * curves_new_nomain(int points_num, int curves_num)
Definition: curves.cc:367
struct blender::compositor::@179::@181 task
static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &options, const AllPointCloudsInfo &all_pointclouds_info, const Span< RealizePointCloudTask > tasks, const OrderedAttributes &ordered_attributes, GeometrySet &r_realized_geometry)
static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info, const GeometrySet &geometry_set, const float4x4 &base_transform, const InstanceContext &base_instance_context)
static AllCurvesInfo preprocess_curves(const GeometrySet &geometry_set, const RealizeInstancesOptions &options)
static OrderedAttributes gather_generic_curve_attributes_to_propagate(const GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, bool &r_create_id)
static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set, const RealizeInstancesOptions &options)
static void execute_realize_pointcloud_task(const RealizeInstancesOptions &options, const RealizePointCloudTask &task, const OrderedAttributes &ordered_attributes, MutableSpan< GSpanAttributeWriter > dst_attribute_writers, MutableSpan< int > all_dst_ids, MutableSpan< float3 > all_dst_positions)
static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options, const AllMeshesInfo &all_meshes_info, const Span< RealizeMeshTask > tasks, const OrderedAttributes &ordered_attributes, const VectorSet< Material * > &ordered_materials, GeometrySet &r_realized_geometry)
static void foreach_geometry_in_reference(const InstanceReference &reference, const float4x4 &base_transform, const uint32_t id, FunctionRef< void(const GeometrySet &geometry_set, const float4x4 &transform, uint32_t id)> fn)
static void threaded_copy(const GSpan src, GMutableSpan dst)
static void create_result_ids(const RealizeInstancesOptions &options, Span< int > stored_ids, const int task_id, MutableSpan< int > dst_ids)
static void remove_id_attribute_from_instances(GeometrySet &geometry_set)
static AllPointCloudsInfo preprocess_pointclouds(const GeometrySet &geometry_set, const RealizeInstancesOptions &options)
static void gather_meshes_to_realize(const GeometrySet &geometry_set, VectorSet< const Mesh * > &r_meshes)
static void gather_curves_to_realize(const GeometrySet &geometry_set, VectorSet< const Curves * > &r_curves)
static void execute_realize_curve_task(const RealizeInstancesOptions &options, const AllCurvesInfo &all_curves_info, const RealizeCurveTask &task, const OrderedAttributes &ordered_attributes, bke::CurvesGeometry &dst_curves, MutableSpan< GSpanAttributeWriter > dst_attribute_writers, MutableSpan< int > all_dst_ids, MutableSpan< float3 > all_handle_left, MutableSpan< float3 > all_handle_right, MutableSpan< float > all_radii, MutableSpan< int > all_resolutions)
static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info, const InstancesComponent &instances_component, const float4x4 &base_transform, const InstanceContext &base_instance_context)
GeometrySet realize_instances(GeometrySet geometry_set, const RealizeInstancesOptions &options)
static void threaded_fill(const GPointer value, GMutableSpan dst)
static void copy_generic_attributes_to_result(const Span< std::optional< GVArraySpan >> src_attributes, const AttributeFallbacksArray &attribute_fallbacks, const OrderedAttributes &ordered_attributes, const FunctionRef< IndexRange(eAttrDomain)> &range_fn, MutableSpan< GSpanAttributeWriter > dst_attribute_writers)
static Vector< std::pair< int, GSpan > > prepare_attribute_fallbacks(GatherTasksInfo &gather_info, const InstancesComponent &instances_component, const OrderedAttributes &ordered_attributes)
static void gather_pointclouds_to_realize(const GeometrySet &geometry_set, VectorSet< const PointCloud * > &r_pointclouds)
static OrderedAttributes gather_generic_mesh_attributes_to_propagate(const GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, bool &r_create_id)
static OrderedAttributes gather_generic_pointcloud_attributes_to_propagate(const GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, bool &r_create_id)
static void execute_realize_mesh_task(const RealizeInstancesOptions &options, const RealizeMeshTask &task, const OrderedAttributes &ordered_attributes, Mesh &dst_mesh, MutableSpan< GSpanAttributeWriter > dst_attribute_writers, MutableSpan< int > all_dst_vertex_ids)
static void copy_transformed_positions(const Span< float3 > src, const float4x4 &transform, MutableSpan< float3 > dst)
static void execute_realize_curve_tasks(const RealizeInstancesOptions &options, const AllCurvesInfo &all_curves_info, const Span< RealizeCurveTask > tasks, const OrderedAttributes &ordered_attributes, GeometrySet &r_realized_geometry)
static Type to_type(const eGPUType type)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
Definition: BLI_task.hh:51
MutableSpan< float3 > positions
#define hash
Definition: noise.c:153
unsigned int uint32_t
Definition: stdint.h:80
float instance_offset[3]
CurvesGeometry geometry
const PointCloud * get_pointcloud_for_read() const
GeometryComponent & get_component_for_write(GeometryComponentType component_type)
blender::Vector< const GeometryComponent * > get_components_for_read() const
bool has(const GeometryComponentType component_type) const
const GeometryComponent * get_component_for_read(GeometryComponentType component_type) const
const Mesh * get_mesh_for_read() const
const Curves * get_curves_for_read() const
void gather_attributes_for_propagation(blender::Span< GeometryComponentType > component_types, GeometryComponentType dst_component_type, bool include_instances, blender::Map< blender::bke::AttributeIDRef, blender::bke::AttributeKind > &r_attributes) const
void add(const GeometryComponent &component)
bool has_instances() const
void modify_geometry_sets(ForeachSubGeometryCallback callback)
struct MEdge * medge
struct MVert * mvert
struct Material ** mat
int totedge
ListBase vertex_group_names
int totvert
struct MLoop * mloop
int totpoly
short totcol
int totloop
struct MPoly * mpoly
float values[4][4]
Definition: BLI_float4x4.hh:13
VectorSet< const Curves * > order
Array< RealizeCurveInfo > realize_info
VectorSet< Material * > materials
VectorSet< const Mesh * > order
Array< MeshRealizeInfo > realize_info
Array< PointCloudRealizeInfo > realize_info
VectorSet< const PointCloud * > order
MeshElementStartIndices mesh_offsets
CurvesElementStartIndices curves_offsets
const AllPointCloudsInfo & pointclouds
Vector< std::unique_ptr< GArray<> > > & r_temporary_arrays
Vector< RealizeMeshTask > mesh_tasks
Vector< RealizePointCloudTask > pointcloud_tasks
UserCounter< const VolumeComponent > first_volume
Vector< RealizeCurveTask > curve_tasks
UserCounter< const GeometryComponentEditData > first_edit_data
InstanceContext(const GatherTasksInfo &gather_info)
Array< std::optional< GVArraySpan > > attributes
VectorSet< AttributeIDRef > ids
Array< std::optional< GVArraySpan > > attributes
Array< std::optional< GVArraySpan > > attributes
AttributeFallbacksArray attribute_fallbacks
CurvesElementStartIndices start_indices
AttributeFallbacksArray attribute_fallbacks
MeshElementStartIndices start_indices
const PointCloudRealizeInfo * pointcloud_info
ParamHandle ** handles