Blender V4.3
realize_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
7
9
10#include "BLI_array_utils.hh"
11#include "BLI_noise.hh"
12
13#include "BKE_curves.hh"
14#include "BKE_customdata.hh"
15#include "BKE_deform.hh"
18#include "BKE_grease_pencil.hh"
19#include "BKE_instances.hh"
20#include "BKE_material.h"
21#include "BKE_mesh.hh"
22#include "BKE_pointcloud.hh"
24
25namespace blender::geometry {
26
34
42
43 int size() const
44 {
45 return this->kinds.size();
46 }
47
49 {
50 return this->kinds.index_range();
51 }
52};
53
65
75
87
90 int vertex = 0;
91 int edge = 0;
92 int face = 0;
93 int loop = 0;
94};
95
112
122
162
165 int point = 0;
166 int curve = 0;
167};
168
179
187
195
200
211
229
244
255
264
277
285
316
332 uint32_t id = 0;
333
335 : pointclouds(gather_info.pointclouds.attributes.size()),
336 meshes(gather_info.meshes.attributes.size()),
337 curves(gather_info.curves.attributes.size()),
338 grease_pencils(gather_info.grease_pencils.attributes.size()),
339 instances(gather_info.instances_attriubutes.size())
340 {
341 // empty
342 }
343};
344
346{
347 int64_t points_num = 0;
348 if (!tasks.pointcloud_tasks.is_empty()) {
349 const RealizePointCloudTask &task = tasks.pointcloud_tasks.last();
350 points_num += task.start_index + task.pointcloud_info->pointcloud->totpoint;
351 }
352 if (!tasks.mesh_tasks.is_empty()) {
353 const RealizeMeshTask &task = tasks.mesh_tasks.last();
354 points_num += task.start_indices.vertex + task.mesh_info->mesh->verts_num;
355 }
356 if (!tasks.curve_tasks.is_empty()) {
357 const RealizeCurveTask &task = tasks.curve_tasks.last();
358 points_num += task.start_indices.point + task.curve_info->curves->geometry.point_num;
359 }
360 return points_num;
361}
362
363static bool skip_transform(const float4x4 &transform)
364{
365 return math::is_equal(transform, float4x4::identity(), 1e-6f);
366}
367
369 const float4x4 &transform,
371{
372 if (skip_transform(transform)) {
373 dst.copy_from(src);
374 }
375 else {
376 threading::parallel_for(src.index_range(), 1024, [&](const IndexRange range) {
377 for (const int i : range) {
378 dst[i] = math::transform_point(transform, src[i]);
379 }
380 });
381 }
382}
383
384static void transform_positions(const float4x4 &transform, MutableSpan<float3> positions)
385{
386 threading::parallel_for(positions.index_range(), 1024, [&](const IndexRange range) {
387 for (const int i : range) {
388 positions[i] = math::transform_point(transform, positions[i]);
389 }
390 });
391}
392
394 const float4x4 &transform,
396{
397 const float3x3 normal_transform = math::transpose(math::invert(float3x3(transform)));
398 if (math::is_equal(normal_transform, float3x3::identity(), 1e-6f)) {
399 dst.copy_from(src);
400 }
401 else {
402 threading::parallel_for(src.index_range(), 1024, [&](const IndexRange range) {
403 for (const int i : range) {
404 dst[i] = normal_transform * src[i];
405 }
406 });
407 }
408}
409
410static void threaded_copy(const GSpan src, GMutableSpan dst)
411{
412 BLI_assert(src.size() == dst.size());
413 BLI_assert(src.type() == dst.type());
414 threading::parallel_for(IndexRange(src.size()), 1024, [&](const IndexRange range) {
415 src.type().copy_construct_n(src.slice(range).data(), dst.slice(range).data(), range.size());
416 });
417}
418
419static void threaded_fill(const GPointer value, GMutableSpan dst)
420{
421 BLI_assert(*value.type() == dst.type());
422 threading::parallel_for(IndexRange(dst.size()), 1024, [&](const IndexRange range) {
423 value.type()->fill_construct_n(value.get(), dst.slice(range).data(), range.size());
424 });
425}
426
428 const Span<std::optional<GVArraySpan>> src_attributes,
429 const AttributeFallbacksArray &attribute_fallbacks,
430 const OrderedAttributes &ordered_attributes,
431 const FunctionRef<IndexRange(bke::AttrDomain)> &range_fn,
432 MutableSpan<GSpanAttributeWriter> dst_attribute_writers)
433{
434 threading::parallel_for(
435 dst_attribute_writers.index_range(), 10, [&](const IndexRange attribute_range) {
436 for (const int attribute_index : attribute_range) {
437 const bke::AttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
438 const IndexRange element_slice = range_fn(domain);
439
440 GMutableSpan dst_span = dst_attribute_writers[attribute_index].span.slice(element_slice);
441 if (src_attributes[attribute_index].has_value()) {
442 threaded_copy(*src_attributes[attribute_index], dst_span);
443 }
444 else {
445 const CPPType &cpp_type = dst_span.type();
446 const void *fallback = attribute_fallbacks.array[attribute_index] == nullptr ?
447 cpp_type.default_value() :
448 attribute_fallbacks.array[attribute_index];
449 threaded_fill({cpp_type, fallback}, dst_span);
450 }
451 }
452 });
453}
454
456 const Span<int> stored_ids,
457 const int task_id,
458 MutableSpan<int> dst_ids)
459{
460 if (options.keep_original_ids) {
461 if (stored_ids.is_empty()) {
462 dst_ids.fill(0);
463 }
464 else {
465 dst_ids.copy_from(stored_ids);
466 }
467 }
468 else {
469 if (stored_ids.is_empty()) {
470 threading::parallel_for(dst_ids.index_range(), 1024, [&](const IndexRange range) {
471 for (const int i : range) {
472 dst_ids[i] = noise::hash(task_id, i);
473 }
474 });
475 }
476 else {
477 threading::parallel_for(dst_ids.index_range(), 1024, [&](const IndexRange range) {
478 for (const int i : range) {
479 dst_ids[i] = noise::hash(task_id, stored_ids[i]);
480 }
481 });
482 }
483 }
484}
485
486/* -------------------------------------------------------------------- */
490/* Forward declaration. */
491static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
492 const int current_depth,
493 const int target_depth,
494 const bke::GeometrySet &geometry_set,
495 const float4x4 &base_transform,
496 const InstanceContext &base_instance_context);
497
504 GatherTasksInfo &gather_info,
505 const Instances &instances,
506 const OrderedAttributes &ordered_attributes)
507{
508 Vector<std::pair<int, GSpan>> attributes_to_override;
509 const bke::AttributeAccessor attributes = instances.attributes();
510 attributes.foreach_attribute([&](const bke::AttributeIter &iter) {
511 const int attribute_index = ordered_attributes.ids.index_of_try(iter.name);
512 if (attribute_index == -1) {
513 /* The attribute is not propagated to the final geometry. */
514 return;
515 }
516 const bke::GAttributeReader attribute = iter.get();
517 if (!attribute || !attribute.varray.is_span()) {
518 return;
519 }
520 GSpan span = attribute.varray.get_internal_span();
521 const eCustomDataType expected_type = ordered_attributes.kinds[attribute_index].data_type;
522 if (iter.data_type != expected_type) {
523 const CPPType &from_type = span.type();
524 const CPPType &to_type = *bke::custom_data_type_to_cpp_type(expected_type);
525 const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions();
526 if (!conversions.is_convertible(from_type, to_type)) {
527 /* Ignore the attribute because it can not be converted to the desired type. */
528 return;
529 }
530 /* Convert the attribute on the instances component to the expected attribute type. */
531 std::unique_ptr<GArray<>> temporary_array = std::make_unique<GArray<>>(
532 to_type, instances.instances_num());
533 conversions.convert_to_initialized_n(span, temporary_array->as_mutable_span());
534 span = temporary_array->as_span();
535 gather_info.r_temporary_arrays.append(std::move(temporary_array));
536 }
537 attributes_to_override.append({attribute_index, span});
538 });
539 return attributes_to_override;
540}
541
547 const InstanceReference &reference,
548 const float4x4 &base_transform,
549 const uint32_t id,
550 FunctionRef<void(const bke::GeometrySet &geometry_set, const float4x4 &transform, uint32_t id)>
551 fn)
552{
553 bke::GeometrySet geometry_set;
554 reference.to_geometry_set(geometry_set);
555 fn(geometry_set, base_transform, id);
556}
557
559 const int current_depth,
560 const int target_depth,
561 const Instances &instances,
562 const float4x4 &base_transform,
563 const InstanceContext &base_instance_context)
564{
565 const Span<InstanceReference> references = instances.references();
566 const Span<int> handles = instances.reference_handles();
567 const Span<float4x4> transforms = instances.transforms();
568
569 Span<int> stored_instance_ids;
570 if (gather_info.create_id_attribute_on_any_component) {
571 bke::AttributeReader ids = instances.attributes().lookup<int>("id");
572 if (ids) {
573 stored_instance_ids = ids.varray.get_internal_span();
574 }
575 }
576
577 /* Prepare attribute fallbacks. */
578 InstanceContext instance_context = base_instance_context;
579 Vector<std::pair<int, GSpan>> pointcloud_attributes_to_override = prepare_attribute_fallbacks(
580 gather_info, instances, gather_info.pointclouds.attributes);
581 Vector<std::pair<int, GSpan>> mesh_attributes_to_override = prepare_attribute_fallbacks(
582 gather_info, instances, gather_info.meshes.attributes);
583 Vector<std::pair<int, GSpan>> curve_attributes_to_override = prepare_attribute_fallbacks(
584 gather_info, instances, gather_info.curves.attributes);
585 Vector<std::pair<int, GSpan>> grease_pencil_attributes_to_override = prepare_attribute_fallbacks(
586 gather_info, instances, gather_info.grease_pencils.attributes);
587 Vector<std::pair<int, GSpan>> instance_attributes_to_override = prepare_attribute_fallbacks(
588 gather_info, instances, gather_info.instances_attriubutes);
589
590 const bool is_top_level = current_depth == 0;
591 /* If at top level, get instance indices from selection field, else use all instances. */
592 const IndexMask indices = is_top_level ? gather_info.selection :
593 IndexMask(IndexRange(instances.instances_num()));
594 indices.foreach_index([&](const int i) {
595 /* If at top level, retrieve depth from gather_info, else continue with target_depth. */
596 const int child_target_depth = is_top_level ? gather_info.depths[i] : target_depth;
597 const int handle = handles[i];
598 const float4x4 &transform = transforms[i];
599 const InstanceReference &reference = references[handle];
600 const float4x4 new_base_transform = base_transform * transform;
601
602 /* Update attribute fallbacks for the current instance. */
603 for (const std::pair<int, GSpan> &pair : pointcloud_attributes_to_override) {
604 instance_context.pointclouds.array[pair.first] = pair.second[i];
605 }
606 for (const std::pair<int, GSpan> &pair : mesh_attributes_to_override) {
607 instance_context.meshes.array[pair.first] = pair.second[i];
608 }
609 for (const std::pair<int, GSpan> &pair : curve_attributes_to_override) {
610 instance_context.curves.array[pair.first] = pair.second[i];
611 }
612 for (const std::pair<int, GSpan> &pair : grease_pencil_attributes_to_override) {
613 instance_context.grease_pencils.array[pair.first] = pair.second[i];
614 }
615 for (const std::pair<int, GSpan> &pair : instance_attributes_to_override) {
616 instance_context.instances.array[pair.first] = pair.second[i];
617 }
618
619 uint32_t local_instance_id = 0;
620 if (gather_info.create_id_attribute_on_any_component) {
621 if (stored_instance_ids.is_empty()) {
622 local_instance_id = uint32_t(i);
623 }
624 else {
625 local_instance_id = uint32_t(stored_instance_ids[i]);
626 }
627 }
628 const uint32_t instance_id = noise::hash(base_instance_context.id, local_instance_id);
629
630 /* Add realize tasks for all referenced geometry sets recursively. */
632 new_base_transform,
633 instance_id,
634 [&](const bke::GeometrySet &instance_geometry_set,
635 const float4x4 &transform,
636 const uint32_t id) {
637 instance_context.id = id;
639 current_depth + 1,
640 child_target_depth,
641 instance_geometry_set,
642 transform,
643 instance_context);
644 });
645 });
646}
647
652 const int current_depth,
653 const int target_depth,
654 const bke::GeometrySet &geometry_set,
655 const float4x4 &base_transform,
656 const InstanceContext &base_instance_context)
657{
658 for (const bke::GeometryComponent *component : geometry_set.get_components()) {
659 const bke::GeometryComponent::Type type = component->type();
660 switch (type) {
661 case bke::GeometryComponent::Type::Mesh: {
662 const Mesh *mesh = (*static_cast<const bke::MeshComponent *>(component)).get();
663 if (mesh != nullptr && mesh->verts_num > 0) {
664 const int mesh_index = gather_info.meshes.order.index_of(mesh);
665 const MeshRealizeInfo &mesh_info = gather_info.meshes.realize_info[mesh_index];
666 gather_info.r_tasks.mesh_tasks.append({gather_info.r_offsets.mesh_offsets,
667 &mesh_info,
668 base_transform,
669 base_instance_context.meshes,
670 base_instance_context.id});
671 gather_info.r_offsets.mesh_offsets.vertex += mesh->verts_num;
672 gather_info.r_offsets.mesh_offsets.edge += mesh->edges_num;
673 gather_info.r_offsets.mesh_offsets.loop += mesh->corners_num;
674 gather_info.r_offsets.mesh_offsets.face += mesh->faces_num;
675 }
676 break;
677 }
678 case bke::GeometryComponent::Type::PointCloud: {
679 const auto &pointcloud_component = *static_cast<const bke::PointCloudComponent *>(
680 component);
681 const PointCloud *pointcloud = pointcloud_component.get();
682 if (pointcloud != nullptr && pointcloud->totpoint > 0) {
683 const int pointcloud_index = gather_info.pointclouds.order.index_of(pointcloud);
684 const PointCloudRealizeInfo &pointcloud_info =
685 gather_info.pointclouds.realize_info[pointcloud_index];
686 gather_info.r_tasks.pointcloud_tasks.append({gather_info.r_offsets.pointcloud_offset,
687 &pointcloud_info,
688 base_transform,
689 base_instance_context.pointclouds,
690 base_instance_context.id});
691 gather_info.r_offsets.pointcloud_offset += pointcloud->totpoint;
692 }
693 break;
694 }
695 case bke::GeometryComponent::Type::Curve: {
696 const auto &curve_component = *static_cast<const bke::CurveComponent *>(component);
697 const Curves *curves = curve_component.get();
698 if (curves != nullptr && curves->geometry.curve_num > 0) {
699 const int curve_index = gather_info.curves.order.index_of(curves);
700 const RealizeCurveInfo &curve_info = gather_info.curves.realize_info[curve_index];
701 gather_info.r_tasks.curve_tasks.append({gather_info.r_offsets.curves_offsets,
702 &curve_info,
703 base_transform,
704 base_instance_context.curves,
705 base_instance_context.id});
706 gather_info.r_offsets.curves_offsets.point += curves->geometry.point_num;
707 gather_info.r_offsets.curves_offsets.curve += curves->geometry.curve_num;
708 }
709 break;
710 }
711 case bke::GeometryComponent::Type::GreasePencil: {
712 const auto &grease_pencil_component = *static_cast<const bke::GreasePencilComponent *>(
713 component);
714 const GreasePencil *grease_pencil = grease_pencil_component.get();
715 if (grease_pencil != nullptr && !grease_pencil->layers().is_empty()) {
716 const int grease_pencil_index = gather_info.grease_pencils.order.index_of(grease_pencil);
717 const GreasePencilRealizeInfo &grease_pencil_info =
718 gather_info.grease_pencils.realize_info[grease_pencil_index];
719 gather_info.r_tasks.grease_pencil_tasks.append(
721 &grease_pencil_info,
722 base_transform,
723 base_instance_context.grease_pencils});
724 gather_info.r_offsets.grease_pencil_layer_offset += grease_pencil->layers().size();
725 }
726 break;
727 }
728 case bke::GeometryComponent::Type::Instance: {
729 if (current_depth == target_depth) {
730 gather_info.instances.attribute_fallback.append(base_instance_context.instances);
731 gather_info.instances.instances_components_to_merge.append(component->copy());
732 gather_info.instances.instances_components_transforms.append(base_transform);
733 }
734 else {
735 const Instances *instances =
736 (*static_cast<const bke::InstancesComponent *>(component)).get();
737 if (instances != nullptr && instances->instances_num() > 0) {
739 current_depth,
740 target_depth,
741 *instances,
742 base_transform,
743 base_instance_context);
744 }
745 }
746 break;
747 }
748 case bke::GeometryComponent::Type::Volume: {
749 if (!gather_info.r_tasks.first_volume) {
750 const bke::VolumeComponent *volume_component = static_cast<const bke::VolumeComponent *>(
751 component);
752 volume_component->add_user();
754 volume_component);
755 }
756 break;
757 }
758 case bke::GeometryComponent::Type::Edit: {
759 const auto *edit_component = static_cast<const bke::GeometryComponentEditData *>(
760 component);
761 if (edit_component->gizmo_edit_hints_ || edit_component->curves_edit_hints_) {
762 gather_info.r_tasks.edit_data_tasks.append({edit_component, base_transform});
763 }
764 break;
765 }
766 }
767 }
768}
769
771 const bke::GeometrySet &geometry,
772 const bke::GeometryComponent::Type component_type,
774 const int current_depth,
775 const std::optional<int> max_depth,
776 Set<bke::GeometryComponentPtr> &r_components)
777{
778 if (const bke::GeometryComponent *component = geometry.get_component(component_type)) {
779 if (r_components.add_as(component)) {
780 component->add_user();
781 }
782 }
783 if (current_depth == max_depth) {
784 return;
785 }
786 const auto *instances_component = geometry.get_component<bke::InstancesComponent>();
787 if (!instances_component) {
788 return;
789 }
790 const bke::Instances *instances = instances_component->get();
791 if (!instances) {
792 return;
793 }
794 if (options.realize_instance_attributes) {
795 if (r_components.add_as(instances_component)) {
796 instances_component->add_user();
797 }
798 }
799 for (const bke::InstanceReference &reference : instances->references()) {
800 bke::GeometrySet reference_geometry;
801 reference.to_geometry_set(reference_geometry);
803 reference_geometry, component_type, options, current_depth + 1, max_depth, r_components);
804 }
805}
806
808 const bke::GeometrySet &geometry,
809 const bke::GeometryComponent::Type component_type,
811 const VariedDepthOptions &varied_depth_option,
812 Set<bke::GeometryComponentPtr> &r_components)
813{
814 if (const bke::GeometryComponent *component = geometry.get_component(component_type)) {
815 if (r_components.add_as(component)) {
816 component->add_user();
817 }
818 }
819 const auto *instances_component = geometry.get_component<bke::InstancesComponent>();
820 if (!instances_component) {
821 return;
822 }
823 const bke::Instances *instances = instances_component->get();
824 if (!instances) {
825 return;
826 }
827
828 const Span<bke::InstanceReference> references = instances->references();
829 const Span<int> handles = instances->reference_handles();
830 const int references_num = references.size();
831 Array<std::optional<int>> max_reference_depth(references_num, 0);
832
833 varied_depth_option.selection.foreach_index([&](const int instance_i) {
834 const int reference_i = handles[instance_i];
835 const int instance_depth = varied_depth_option.depths[instance_i];
836 std::optional<int> &max_depth = max_reference_depth[reference_i];
837 if (!max_depth.has_value()) {
838 /* Is already at max depth. */
839 return;
840 }
841 if (instance_depth == VariedDepthOptions::MAX_DEPTH) {
842 max_depth.reset();
843 return;
844 }
845 max_depth = std::max<int>(*max_depth, instance_depth);
846 });
847
848 bool is_anything_realized = false;
849 for (const int reference_i : IndexRange(references_num)) {
850 const std::optional<int> max_depth = max_reference_depth[reference_i];
851 if (max_depth == 0) {
852 continue;
853 }
854 const bke::InstanceReference &reference = references[reference_i];
855 bke::GeometrySet reference_geometry;
856 reference.to_geometry_set(reference_geometry);
858 reference_geometry, component_type, options, 1, max_depth, r_components);
859 is_anything_realized = true;
860 }
861
862 if (is_anything_realized) {
863 if (options.realize_instance_attributes) {
864 if (r_components.add_as(instances_component)) {
865 instances_component->add_user();
866 }
867 }
868 }
869}
870
872 const bke::GeometrySet &geometry,
873 const bke::GeometryComponent::Type component_type,
875 const VariedDepthOptions &varied_depth_option)
876{
877 const bke::AttributeFilter &attribute_filter = options.attribute_filter;
878
879 const bke::InstancesComponent *top_level_instances_component =
880 geometry.get_component<bke::InstancesComponent>();
881 const int top_level_instances_num = top_level_instances_component ?
882 top_level_instances_component->attribute_domain_size(
883 AttrDomain::Instance) :
884 0;
885
886 /* Needs to take ownership because some components are only temporary otherwise. */
888 if (varied_depth_option.depths.get_if_single() == VariedDepthOptions::MAX_DEPTH &&
889 varied_depth_option.selection.size() == top_level_instances_num)
890 {
891 /* In this case we don't have to iterate over all instances, just over the references. */
893 geometry, component_type, options, 0, std::nullopt, components);
894 }
895 else {
897 geometry, component_type, options, varied_depth_option, components);
898 }
899
900 /* Actually gather the attributes to propagate from the found components. */
901 Map<StringRef, AttributeKind> attributes_to_propagate;
902 for (const bke::GeometryComponentPtr &component : components) {
903 const bke::AttributeAccessor attributes = *component->attributes();
904 attributes.foreach_attribute([&](const bke::AttributeIter &iter) {
905 if (iter.is_builtin) {
906 if (!bke::attribute_is_builtin_on_component_type(component_type, iter.name)) {
907 /* Don't propagate built-in attributes that are not built-in on the
908 * destination component. */
909 return;
910 }
911 }
912 if (iter.data_type == CD_PROP_STRING) {
913 /* Propagating string attributes is not supported yet. */
914 return;
915 }
916 if (attribute_filter.allow_skip(iter.name)) {
917 return;
918 }
919 AttrDomain dst_domain = iter.domain;
920 if (component_type != bke::GeometryComponent::Type::Instance &&
921 dst_domain == AttrDomain::Instance)
922 {
923 /* Instance attributes are realized on the point domain currently. */
924 dst_domain = AttrDomain::Point;
925 }
926 auto add = [&](AttributeKind *kind) {
927 kind->domain = dst_domain;
928 kind->data_type = iter.data_type;
929 };
930 auto modify = [&](AttributeKind *kind) {
931 kind->domain = bke::attribute_domain_highest_priority({kind->domain, dst_domain});
932 kind->data_type = bke::attribute_data_type_highest_complexity(
933 {kind->data_type, iter.data_type});
934 };
935 attributes_to_propagate.add_or_modify(iter.name, add, modify);
936 });
937 }
938
939 return attributes_to_propagate;
940}
941
944/* -------------------------------------------------------------------- */
949 const bke::GeometrySet &in_geometry_set,
951 const VariedDepthOptions &varied_depth_option)
952{
954 in_geometry_set, bke::GeometryComponent::Type::Instance, options, varied_depth_option);
955 attributes_to_propagate.pop_try("id");
956 OrderedAttributes ordered_attributes;
957 for (const auto item : attributes_to_propagate.items()) {
958 ordered_attributes.ids.add_new(item.key);
959 ordered_attributes.kinds.append(item.value);
960 }
961 return ordered_attributes;
962}
963
965 const Span<bke::GeometryComponentPtr> src_components,
966 Span<blender::float4x4> src_base_transforms,
967 OrderedAttributes all_instances_attributes,
969 bke::GeometrySet &r_realized_geometry)
970{
971 BLI_assert(src_components.size() == src_base_transforms.size() &&
972 src_components.size() == attribute_fallback.size());
973 if (src_components.is_empty()) {
974 return;
975 }
976
977 Array<int> offsets_data(src_components.size() + 1);
978 for (const int component_index : src_components.index_range()) {
979 const bke::InstancesComponent &src_component = static_cast<const bke::InstancesComponent &>(
980 *src_components[component_index]);
981 offsets_data[component_index] = src_component.get()->instances_num();
982 }
983 const OffsetIndices offsets = offset_indices::accumulate_counts_to_offsets(offsets_data);
984
985 std::unique_ptr<bke::Instances> dst_instances = std::make_unique<bke::Instances>();
986 dst_instances->resize(offsets.total_size());
987
988 /* Makes sure generic output attributes exists. */
989 for (const int attribute_index : all_instances_attributes.index_range()) {
990 const bke::AttrDomain domain = bke::AttrDomain::Instance;
991 const StringRef id = all_instances_attributes.ids[attribute_index];
992 const eCustomDataType type = all_instances_attributes.kinds[attribute_index].data_type;
993 dst_instances->attributes_for_write()
994 .lookup_or_add_for_write_only_span(id, domain, type)
995 .finish();
996 }
997
998 MutableSpan<float4x4> all_transforms = dst_instances->transforms_for_write();
999 MutableSpan<int> all_handles = dst_instances->reference_handles_for_write();
1000
1001 for (const int component_index : src_components.index_range()) {
1002 const bke::InstancesComponent &src_component = static_cast<const bke::InstancesComponent &>(
1003 *src_components[component_index]);
1004 const bke::Instances &src_instances = *src_component.get();
1005 const blender::float4x4 &src_base_transform = src_base_transforms[component_index];
1006 const Span<const void *> attribute_fallback_array = attribute_fallback[component_index].array;
1007 const Span<bke::InstanceReference> src_references = src_instances.references();
1008 Array<int> handle_map(src_references.size());
1009
1010 for (const int src_handle : src_references.index_range()) {
1011 handle_map[src_handle] = dst_instances->add_reference(src_references[src_handle]);
1012 }
1013 const IndexRange dst_range = offsets[component_index];
1014 for (const int attribute_index : all_instances_attributes.index_range()) {
1015 const StringRef id = all_instances_attributes.ids[attribute_index];
1016 const eCustomDataType type = all_instances_attributes.kinds[attribute_index].data_type;
1017 const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(type);
1018 BLI_assert(cpp_type != nullptr);
1019 bke::GSpanAttributeWriter write_attribute =
1020 dst_instances->attributes_for_write().lookup_for_write_span(id);
1021 GMutableSpan dst_span = write_attribute.span;
1022
1023 const void *attribute_ptr;
1024 if (attribute_fallback_array[attribute_index] != nullptr) {
1025 attribute_ptr = attribute_fallback_array[attribute_index];
1026 }
1027 else {
1028 attribute_ptr = cpp_type->default_value();
1029 }
1030
1031 cpp_type->fill_assign_n(attribute_ptr, dst_span.slice(dst_range).data(), dst_range.size());
1032 write_attribute.finish();
1033 }
1034
1035 const Span<int> src_handles = src_instances.reference_handles();
1036 array_utils::gather(handle_map.as_span(), src_handles, all_handles.slice(dst_range));
1037 array_utils::copy(src_instances.transforms(), all_transforms.slice(dst_range));
1038
1039 for (blender::float4x4 &transform : all_transforms.slice(dst_range)) {
1040 transform = src_base_transform * transform;
1041 }
1042 }
1043
1044 r_realized_geometry.replace_instances(dst_instances.release());
1045 auto &dst_component = r_realized_geometry.get_component_for_write<bke::InstancesComponent>();
1046
1047 Vector<const bke::GeometryComponent *> for_join_attributes;
1048 for (bke::GeometryComponentPtr component : src_components) {
1049 for_join_attributes.append(component.get());
1050 }
1051 /* Join attribute values from the 'unselected' instances, as they aren't included otherwise.
1052 * Omit instance_transform and .reference_index to prevent them from overwriting the correct
1053 * attributes of the realized instances. */
1054 join_attributes(for_join_attributes, dst_component, {".reference_index", "instance_transform"});
1055}
1056
1059/* -------------------------------------------------------------------- */
1064 const bke::GeometrySet &in_geometry_set,
1066 const VariedDepthOptions &varied_depth_option,
1067 bool &r_create_radii,
1068 bool &r_create_id)
1069{
1071 in_geometry_set, bke::GeometryComponent::Type::PointCloud, options, varied_depth_option);
1072 attributes_to_propagate.remove("position");
1073 r_create_id = attributes_to_propagate.pop_try("id").has_value();
1074 r_create_radii = attributes_to_propagate.pop_try("radius").has_value();
1075 OrderedAttributes ordered_attributes;
1076 for (const auto item : attributes_to_propagate.items()) {
1077 ordered_attributes.ids.add_new(item.key);
1078 ordered_attributes.kinds.append(item.value);
1079 }
1080 return ordered_attributes;
1081}
1082
1083static void gather_pointclouds_to_realize(const bke::GeometrySet &geometry_set,
1084 VectorSet<const PointCloud *> &r_pointclouds)
1085{
1086 if (const PointCloud *pointcloud = geometry_set.get_pointcloud()) {
1087 if (pointcloud->totpoint > 0) {
1088 r_pointclouds.add(pointcloud);
1089 }
1090 }
1091 if (const Instances *instances = geometry_set.get_instances()) {
1092 instances->foreach_referenced_geometry([&](const bke::GeometrySet &instance_geometry_set) {
1093 gather_pointclouds_to_realize(instance_geometry_set, r_pointclouds);
1094 });
1095 }
1096}
1097
1100 const VariedDepthOptions &varied_depth_option)
1101{
1102 AllPointCloudsInfo info;
1104 options,
1105 varied_depth_option,
1107 info.create_id_attribute);
1108
1109 gather_pointclouds_to_realize(geometry_set, info.order);
1110 info.realize_info.reinitialize(info.order.size());
1111 for (const int pointcloud_index : info.realize_info.index_range()) {
1112 PointCloudRealizeInfo &pointcloud_info = info.realize_info[pointcloud_index];
1113 const PointCloud *pointcloud = info.order[pointcloud_index];
1114 pointcloud_info.pointcloud = pointcloud;
1115
1116 /* Access attributes. */
1117 bke::AttributeAccessor attributes = pointcloud->attributes();
1118 pointcloud_info.attributes.reinitialize(info.attributes.size());
1119 for (const int attribute_index : info.attributes.index_range()) {
1120 const StringRef attribute_id = info.attributes.ids[attribute_index];
1121 const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
1122 const bke::AttrDomain domain = info.attributes.kinds[attribute_index].domain;
1123 if (attributes.contains(attribute_id)) {
1124 GVArray attribute = *attributes.lookup_or_default(attribute_id, domain, data_type);
1125 pointcloud_info.attributes[attribute_index].emplace(std::move(attribute));
1126 }
1127 }
1128 if (info.create_id_attribute) {
1129 bke::GAttributeReader ids_attribute = attributes.lookup("id");
1130 if (ids_attribute) {
1131 pointcloud_info.stored_ids = ids_attribute.varray.get_internal_span().typed<int>();
1132 }
1133 }
1134 if (info.create_radius_attribute) {
1135 pointcloud_info.radii = *attributes.lookup_or_default(
1136 "radius", bke::AttrDomain::Point, 0.01f);
1137 }
1138 const VArray<float3> position_attribute = *attributes.lookup_or_default<float3>(
1139 "position", bke::AttrDomain::Point, float3(0));
1140 pointcloud_info.positions = position_attribute.get_internal_span();
1141 }
1142 return info;
1143}
1144
1147 const RealizePointCloudTask &task,
1148 const OrderedAttributes &ordered_attributes,
1149 MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
1150 MutableSpan<float> all_dst_radii,
1151 MutableSpan<int> all_dst_ids,
1152 MutableSpan<float3> all_dst_positions)
1153{
1154 const PointCloudRealizeInfo &pointcloud_info = *task.pointcloud_info;
1155 const PointCloud &pointcloud = *pointcloud_info.pointcloud;
1156 const IndexRange point_slice{task.start_index, pointcloud.totpoint};
1157
1159 pointcloud_info.positions, task.transform, all_dst_positions.slice(point_slice));
1160
1161 /* Create point ids. */
1162 if (!all_dst_ids.is_empty()) {
1164 options, pointcloud_info.stored_ids, task.id, all_dst_ids.slice(point_slice));
1165 }
1166 if (!all_dst_radii.is_empty()) {
1167 pointcloud_info.radii.materialize(all_dst_radii.slice(point_slice));
1168 }
1169
1171 pointcloud_info.attributes,
1172 task.attribute_fallbacks,
1173 ordered_attributes,
1174 [&](const bke::AttrDomain domain) {
1175 BLI_assert(domain == bke::AttrDomain::Point);
1176 UNUSED_VARS_NDEBUG(domain);
1177 return point_slice;
1178 },
1179 dst_attribute_writers);
1180}
1181
1183 const OrderedAttributes &ordered_attributes,
1184 const AttributeFallbacksArray &attribute_fallbacks,
1186{
1187 for (const int attribute_index : ordered_attributes.index_range()) {
1188 const void *value = attribute_fallbacks.array[attribute_index];
1189 if (!value) {
1190 continue;
1191 }
1192 const bke::AttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
1193 const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
1194 const CPPType &cpp_type = *bke::custom_data_type_to_cpp_type(data_type);
1195 GVArray gvaray(GVArray::ForSingle(cpp_type, attributes.domain_size(domain), value));
1196 attributes.add(ordered_attributes.ids[attribute_index],
1197 domain,
1198 data_type,
1199 bke::AttributeInitVArray(std::move(gvaray)));
1200 }
1201}
1203 const AllPointCloudsInfo &all_pointclouds_info,
1204 const Span<RealizePointCloudTask> tasks,
1205 const OrderedAttributes &ordered_attributes,
1206 bke::GeometrySet &r_realized_geometry)
1207{
1208 if (tasks.is_empty()) {
1209 return;
1210 }
1211
1212 if (tasks.size() == 1) {
1213 const RealizePointCloudTask &task = tasks.first();
1214 PointCloud *new_points = BKE_pointcloud_copy_for_eval(task.pointcloud_info->pointcloud);
1215 if (!skip_transform(task.transform)) {
1216 transform_positions(task.transform, new_points->positions_for_write());
1217 new_points->tag_positions_changed();
1218 }
1220 ordered_attributes, task.attribute_fallbacks, new_points->attributes_for_write());
1221 r_realized_geometry.replace_pointcloud(new_points);
1222 return;
1223 }
1224
1225 const RealizePointCloudTask &last_task = tasks.last();
1226 const PointCloud &last_pointcloud = *last_task.pointcloud_info->pointcloud;
1227 const int tot_points = last_task.start_index + last_pointcloud.totpoint;
1228
1229 /* Allocate new point cloud. */
1230 PointCloud *dst_pointcloud = BKE_pointcloud_new_nomain(tot_points);
1231 r_realized_geometry.replace_pointcloud(dst_pointcloud);
1232 bke::MutableAttributeAccessor dst_attributes = dst_pointcloud->attributes_for_write();
1233
1234 const RealizePointCloudTask &first_task = tasks.first();
1235 const PointCloud &first_pointcloud = *first_task.pointcloud_info->pointcloud;
1236 dst_pointcloud->mat = static_cast<Material **>(MEM_dupallocN(first_pointcloud.mat));
1237 dst_pointcloud->totcol = first_pointcloud.totcol;
1238
1240 "position", bke::AttrDomain::Point);
1241
1242 /* Prepare id attribute. */
1243 SpanAttributeWriter<int> point_ids;
1244 if (all_pointclouds_info.create_id_attribute) {
1245 point_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id",
1246 bke::AttrDomain::Point);
1247 }
1248 SpanAttributeWriter<float> point_radii;
1249 if (all_pointclouds_info.create_radius_attribute) {
1250 point_radii = dst_attributes.lookup_or_add_for_write_only_span<float>("radius",
1251 bke::AttrDomain::Point);
1252 }
1253
1254 /* Prepare generic output attributes. */
1255 Vector<GSpanAttributeWriter> dst_attribute_writers;
1256 for (const int attribute_index : ordered_attributes.index_range()) {
1257 const StringRef attribute_id = ordered_attributes.ids[attribute_index];
1258 const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
1259 dst_attribute_writers.append(dst_attributes.lookup_or_add_for_write_only_span(
1260 attribute_id, bke::AttrDomain::Point, data_type));
1261 }
1262
1263 /* Actually execute all tasks. */
1264 threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
1265 for (const int task_index : task_range) {
1266 const RealizePointCloudTask &task = tasks[task_index];
1267 execute_realize_pointcloud_task(options,
1268 task,
1269 ordered_attributes,
1270 dst_attribute_writers,
1271 point_radii.span,
1272 point_ids.span,
1273 positions.span);
1274 }
1275 });
1276
1277 /* Tag modified attributes. */
1278 for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
1279 dst_attribute.finish();
1280 }
1281 positions.finish();
1282 point_radii.finish();
1283 point_ids.finish();
1284}
1285
1288/* -------------------------------------------------------------------- */
1293 const bke::GeometrySet &in_geometry_set,
1295 const VariedDepthOptions &varied_depth_option,
1296 bool &r_create_id,
1297 bool &r_create_material_index)
1298{
1300 in_geometry_set, bke::GeometryComponent::Type::Mesh, options, varied_depth_option);
1301 attributes_to_propagate.remove("position");
1302 attributes_to_propagate.remove(".edge_verts");
1303 attributes_to_propagate.remove(".corner_vert");
1304 attributes_to_propagate.remove(".corner_edge");
1305 r_create_id = attributes_to_propagate.pop_try("id").has_value();
1306 r_create_material_index = attributes_to_propagate.pop_try("material_index").has_value();
1307 OrderedAttributes ordered_attributes;
1308 for (const auto item : attributes_to_propagate.items()) {
1309 ordered_attributes.ids.add_new(item.key);
1310 ordered_attributes.kinds.append(item.value);
1311 }
1312 return ordered_attributes;
1313}
1314
1315static void gather_meshes_to_realize(const bke::GeometrySet &geometry_set,
1316 VectorSet<const Mesh *> &r_meshes)
1317{
1318 if (const Mesh *mesh = geometry_set.get_mesh()) {
1319 if (mesh->verts_num > 0) {
1320 r_meshes.add(mesh);
1321 }
1322 }
1323 if (const Instances *instances = geometry_set.get_instances()) {
1324 instances->foreach_referenced_geometry([&](const bke::GeometrySet &instance_geometry_set) {
1325 gather_meshes_to_realize(instance_geometry_set, r_meshes);
1326 });
1327 }
1328}
1329
1332 const VariedDepthOptions &varied_depth_option)
1333{
1334 AllMeshesInfo info;
1336 geometry_set,
1337 options,
1338 varied_depth_option,
1341
1342 gather_meshes_to_realize(geometry_set, info.order);
1343 for (const Mesh *mesh : info.order) {
1344 if (mesh->totcol == 0) {
1345 /* Add an empty material slot for the default material. */
1346 info.materials.add(nullptr);
1347 }
1348 else {
1349 for (const int slot_index : IndexRange(mesh->totcol)) {
1350 Material *material = mesh->mat[slot_index];
1351 info.materials.add(material);
1352 }
1353 }
1354 }
1356 info.realize_info.reinitialize(info.order.size());
1357 for (const int mesh_index : info.realize_info.index_range()) {
1358 MeshRealizeInfo &mesh_info = info.realize_info[mesh_index];
1359 const Mesh *mesh = info.order[mesh_index];
1360 mesh_info.mesh = mesh;
1361 mesh_info.positions = mesh->vert_positions();
1362 mesh_info.edges = mesh->edges();
1363 mesh_info.faces = mesh->faces();
1364 mesh_info.corner_verts = mesh->corner_verts();
1365 mesh_info.corner_edges = mesh->corner_edges();
1366
1367 /* Create material index mapping. */
1368 mesh_info.material_index_map.reinitialize(std::max<int>(mesh->totcol, 1));
1369 if (mesh->totcol == 0) {
1370 mesh_info.material_index_map.first() = info.materials.index_of(nullptr);
1371 }
1372 else {
1373 for (const int old_slot_index : IndexRange(mesh->totcol)) {
1374 Material *material = mesh->mat[old_slot_index];
1375 const int new_slot_index = info.materials.index_of(material);
1376 mesh_info.material_index_map[old_slot_index] = new_slot_index;
1377 }
1378 }
1379
1380 /* Access attributes. */
1381 bke::AttributeAccessor attributes = mesh->attributes();
1382 mesh_info.attributes.reinitialize(info.attributes.size());
1383 for (const int attribute_index : info.attributes.index_range()) {
1384 const StringRef attribute_id = info.attributes.ids[attribute_index];
1385 const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
1386 const bke::AttrDomain domain = info.attributes.kinds[attribute_index].domain;
1387 if (attributes.contains(attribute_id)) {
1388 GVArray attribute = *attributes.lookup_or_default(attribute_id, domain, data_type);
1389 mesh_info.attributes[attribute_index].emplace(std::move(attribute));
1390 }
1391 }
1392 if (info.create_id_attribute) {
1393 bke::GAttributeReader ids_attribute = attributes.lookup("id");
1394 if (ids_attribute) {
1395 mesh_info.stored_vertex_ids = ids_attribute.varray.get_internal_span().typed<int>();
1396 }
1397 }
1398 mesh_info.material_indices = *attributes.lookup_or_default<int>(
1399 "material_index", bke::AttrDomain::Face, 0);
1400 }
1401
1402 info.no_loose_edges_hint = std::all_of(
1403 info.order.begin(), info.order.end(), [](const Mesh *mesh) {
1404 return mesh->runtime->loose_edges_cache.is_cached() && mesh->loose_edges().count == 0;
1405 });
1406 info.no_loose_verts_hint = std::all_of(
1407 info.order.begin(), info.order.end(), [](const Mesh *mesh) {
1408 return mesh->runtime->loose_verts_cache.is_cached() && mesh->loose_verts().count == 0;
1409 });
1410 info.no_overlapping_hint = std::all_of(
1411 info.order.begin(), info.order.end(), [](const Mesh *mesh) {
1412 return mesh->no_overlapping_topology();
1413 });
1414
1415 return info;
1416}
1417
1419 const RealizeMeshTask &task,
1420 const OrderedAttributes &ordered_attributes,
1421 MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
1422 MutableSpan<float3> all_dst_positions,
1423 MutableSpan<int2> all_dst_edges,
1424 MutableSpan<int> all_dst_face_offsets,
1425 MutableSpan<int> all_dst_corner_verts,
1426 MutableSpan<int> all_dst_corner_edges,
1427 MutableSpan<int> all_dst_vertex_ids,
1428 MutableSpan<int> all_dst_material_indices)
1429{
1430 const MeshRealizeInfo &mesh_info = *task.mesh_info;
1431 const Mesh &mesh = *mesh_info.mesh;
1432
1433 const Span<float3> src_positions = mesh_info.positions;
1434 const Span<int2> src_edges = mesh_info.edges;
1435 const OffsetIndices src_faces = mesh_info.faces;
1436 const Span<int> src_corner_verts = mesh_info.corner_verts;
1437 const Span<int> src_corner_edges = mesh_info.corner_edges;
1438
1439 const IndexRange dst_vert_range(task.start_indices.vertex, src_positions.size());
1440 const IndexRange dst_edge_range(task.start_indices.edge, src_edges.size());
1441 const IndexRange dst_face_range(task.start_indices.face, src_faces.size());
1442 const IndexRange dst_loop_range(task.start_indices.loop, src_corner_verts.size());
1443
1444 MutableSpan<float3> dst_positions = all_dst_positions.slice(dst_vert_range);
1445 MutableSpan<int2> dst_edges = all_dst_edges.slice(dst_edge_range);
1446 MutableSpan<int> dst_face_offsets = all_dst_face_offsets.slice(dst_face_range);
1447 MutableSpan<int> dst_corner_verts = all_dst_corner_verts.slice(dst_loop_range);
1448 MutableSpan<int> dst_corner_edges = all_dst_corner_edges.slice(dst_loop_range);
1449
1450 threading::parallel_for(src_positions.index_range(), 1024, [&](const IndexRange vert_range) {
1451 for (const int i : vert_range) {
1452 dst_positions[i] = math::transform_point(task.transform, src_positions[i]);
1453 }
1454 });
1455 threading::parallel_for(src_edges.index_range(), 1024, [&](const IndexRange edge_range) {
1456 for (const int i : edge_range) {
1457 dst_edges[i] = src_edges[i] + task.start_indices.vertex;
1458 }
1459 });
1460 threading::parallel_for(src_corner_verts.index_range(), 1024, [&](const IndexRange loop_range) {
1461 for (const int i : loop_range) {
1462 dst_corner_verts[i] = src_corner_verts[i] + task.start_indices.vertex;
1463 }
1464 });
1465 threading::parallel_for(src_corner_edges.index_range(), 1024, [&](const IndexRange loop_range) {
1466 for (const int i : loop_range) {
1467 dst_corner_edges[i] = src_corner_edges[i] + task.start_indices.edge;
1468 }
1469 });
1470 threading::parallel_for(src_faces.index_range(), 1024, [&](const IndexRange face_range) {
1471 for (const int i : face_range) {
1472 dst_face_offsets[i] = src_faces[i].start() + task.start_indices.loop;
1473 }
1474 });
1475 if (!all_dst_material_indices.is_empty()) {
1476 const Span<int> material_index_map = mesh_info.material_index_map;
1477 MutableSpan<int> dst_material_indices = all_dst_material_indices.slice(dst_face_range);
1478 if (mesh.totcol == 0) {
1479 /* The material index map contains the index of the null material in the result. */
1480 dst_material_indices.fill(material_index_map.first());
1481 }
1482 else {
1483 if (mesh_info.material_indices.is_single()) {
1484 const int src_index = mesh_info.material_indices.get_internal_single();
1485 const bool valid = IndexRange(mesh.totcol).contains(src_index);
1486 dst_material_indices.fill(valid ? material_index_map[src_index] : 0);
1487 }
1488 else {
1489 VArraySpan<int> indices_span(mesh_info.material_indices);
1490 threading::parallel_for(src_faces.index_range(), 1024, [&](const IndexRange face_range) {
1491 for (const int i : face_range) {
1492 const int src_index = indices_span[i];
1493 const bool valid = IndexRange(mesh.totcol).contains(src_index);
1494 dst_material_indices[i] = valid ? material_index_map[src_index] : 0;
1495 }
1496 });
1497 }
1498 }
1499 }
1500
1501 if (!all_dst_vertex_ids.is_empty()) {
1503 mesh_info.stored_vertex_ids,
1504 task.id,
1505 all_dst_vertex_ids.slice(task.start_indices.vertex, mesh.verts_num));
1506 }
1507
1509 mesh_info.attributes,
1510 task.attribute_fallbacks,
1511 ordered_attributes,
1512 [&](const bke::AttrDomain domain) {
1513 switch (domain) {
1514 case bke::AttrDomain::Point:
1515 return dst_vert_range;
1516 case bke::AttrDomain::Edge:
1517 return dst_edge_range;
1518 case bke::AttrDomain::Face:
1519 return dst_face_range;
1520 case bke::AttrDomain::Corner:
1521 return dst_loop_range;
1522 default:
1523 BLI_assert_unreachable();
1524 return IndexRange();
1525 }
1526 },
1527 dst_attribute_writers);
1528}
1529
1531 const AllMeshesInfo &all_meshes_info,
1532 const Span<RealizeMeshTask> tasks,
1533 const OrderedAttributes &ordered_attributes,
1534 const VectorSet<Material *> &ordered_materials,
1535 bke::GeometrySet &r_realized_geometry)
1536{
1537 if (tasks.is_empty()) {
1538 return;
1539 }
1540
1541 if (tasks.size() == 1) {
1542 const RealizeMeshTask &task = tasks.first();
1543 Mesh *new_mesh = BKE_mesh_copy_for_eval(*task.mesh_info->mesh);
1544 if (!skip_transform(task.transform)) {
1545 transform_positions(task.transform, new_mesh->vert_positions_for_write());
1546 new_mesh->tag_positions_changed();
1547 }
1549 ordered_attributes, task.attribute_fallbacks, new_mesh->attributes_for_write());
1550 r_realized_geometry.replace_mesh(new_mesh);
1551 return;
1552 }
1553
1554 const RealizeMeshTask &last_task = tasks.last();
1555 const Mesh &last_mesh = *last_task.mesh_info->mesh;
1556 const int tot_vertices = last_task.start_indices.vertex + last_mesh.verts_num;
1557 const int tot_edges = last_task.start_indices.edge + last_mesh.edges_num;
1558 const int tot_loops = last_task.start_indices.loop + last_mesh.corners_num;
1559 const int tot_faces = last_task.start_indices.face + last_mesh.faces_num;
1560
1561 Mesh *dst_mesh = BKE_mesh_new_nomain(tot_vertices, tot_edges, tot_faces, tot_loops);
1562 r_realized_geometry.replace_mesh(dst_mesh);
1563 bke::MutableAttributeAccessor dst_attributes = dst_mesh->attributes_for_write();
1564 MutableSpan<float3> dst_positions = dst_mesh->vert_positions_for_write();
1565 MutableSpan<int2> dst_edges = dst_mesh->edges_for_write();
1566 MutableSpan<int> dst_face_offsets = dst_mesh->face_offsets_for_write();
1567 MutableSpan<int> dst_corner_verts = dst_mesh->corner_verts_for_write();
1568 MutableSpan<int> dst_corner_edges = dst_mesh->corner_edges_for_write();
1569
1570 /* Copy settings from the first input geometry set with a mesh. */
1571 const RealizeMeshTask &first_task = tasks.first();
1572 const Mesh &first_mesh = *first_task.mesh_info->mesh;
1573 BKE_mesh_copy_parameters_for_eval(dst_mesh, &first_mesh);
1574 /* The above line also copies vertex group names. We don't want that here because the new
1575 * attributes are added explicitly below. */
1577
1578 /* Add materials. */
1579 for (const int i : IndexRange(ordered_materials.size())) {
1580 Material *material = ordered_materials[i];
1581 BKE_id_material_eval_assign(&dst_mesh->id, i + 1, material);
1582 }
1583
1584 /* Prepare id attribute. */
1585 SpanAttributeWriter<int> vertex_ids;
1586 if (all_meshes_info.create_id_attribute) {
1587 vertex_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id",
1588 bke::AttrDomain::Point);
1589 }
1590 /* Prepare material indices. */
1591 SpanAttributeWriter<int> material_indices;
1592 if (all_meshes_info.create_material_index_attribute) {
1593 material_indices = dst_attributes.lookup_or_add_for_write_only_span<int>(
1594 "material_index", bke::AttrDomain::Face);
1595 }
1596
1597 /* Prepare generic output attributes. */
1598 Vector<GSpanAttributeWriter> dst_attribute_writers;
1599 for (const int attribute_index : ordered_attributes.index_range()) {
1600 const StringRef attribute_id = ordered_attributes.ids[attribute_index];
1601 const bke::AttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
1602 const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
1603 dst_attribute_writers.append(
1604 dst_attributes.lookup_or_add_for_write_only_span(attribute_id, domain, data_type));
1605 }
1606 const char *active_layer = CustomData_get_active_layer_name(&first_mesh.corner_data,
1608 if (active_layer != nullptr) {
1609 int id = CustomData_get_named_layer(&dst_mesh->corner_data, CD_PROP_FLOAT2, active_layer);
1610 if (id >= 0) {
1612 }
1613 }
1614 const char *render_layer = CustomData_get_render_layer_name(&first_mesh.corner_data,
1616 if (render_layer != nullptr) {
1617 int id = CustomData_get_named_layer(&dst_mesh->corner_data, CD_PROP_FLOAT2, render_layer);
1618 if (id >= 0) {
1620 }
1621 }
1622 /* Actually execute all tasks. */
1623 threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
1624 for (const int task_index : task_range) {
1625 const RealizeMeshTask &task = tasks[task_index];
1626 execute_realize_mesh_task(options,
1627 task,
1628 ordered_attributes,
1629 dst_attribute_writers,
1630 dst_positions,
1631 dst_edges,
1632 dst_face_offsets,
1633 dst_corner_verts,
1634 dst_corner_edges,
1635 vertex_ids.span,
1636 material_indices.span);
1637 }
1638 });
1639
1640 /* Tag modified attributes. */
1641 for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
1642 dst_attribute.finish();
1643 }
1644 vertex_ids.finish();
1645 material_indices.finish();
1646
1647 if (all_meshes_info.no_loose_edges_hint) {
1648 dst_mesh->tag_loose_edges_none();
1649 }
1650 if (all_meshes_info.no_loose_verts_hint) {
1651 dst_mesh->tag_loose_verts_none();
1652 }
1653 if (all_meshes_info.no_overlapping_hint) {
1654 dst_mesh->tag_overlapping_none();
1655 }
1656}
1657
1660/* -------------------------------------------------------------------- */
1665 const bke::GeometrySet &in_geometry_set,
1667 const VariedDepthOptions &varied_depth_option,
1668 bool &r_create_id)
1669{
1671 in_geometry_set, bke::GeometryComponent::Type::Curve, options, varied_depth_option);
1672 attributes_to_propagate.remove("position");
1673 attributes_to_propagate.remove("radius");
1674 attributes_to_propagate.remove("nurbs_weight");
1675 attributes_to_propagate.remove("resolution");
1676 attributes_to_propagate.remove("handle_right");
1677 attributes_to_propagate.remove("handle_left");
1678 attributes_to_propagate.remove("custom_normal");
1679 r_create_id = attributes_to_propagate.pop_try("id").has_value();
1680 OrderedAttributes ordered_attributes;
1681 for (const auto item : attributes_to_propagate.items()) {
1682 ordered_attributes.ids.add_new(item.key);
1683 ordered_attributes.kinds.append(item.value);
1684 }
1685 return ordered_attributes;
1686}
1687
1688static void gather_curves_to_realize(const bke::GeometrySet &geometry_set,
1689 VectorSet<const Curves *> &r_curves)
1690{
1691 if (const Curves *curves = geometry_set.get_curves()) {
1692 if (curves->geometry.curve_num != 0) {
1693 r_curves.add(curves);
1694 }
1695 }
1696 if (const Instances *instances = geometry_set.get_instances()) {
1697 instances->foreach_referenced_geometry([&](const bke::GeometrySet &instance_geometry_set) {
1698 gather_curves_to_realize(instance_geometry_set, r_curves);
1699 });
1700 }
1701}
1702
1705 const VariedDepthOptions &varied_depth_option)
1706{
1707 AllCurvesInfo info;
1709 geometry_set, options, varied_depth_option, info.create_id_attribute);
1710
1711 gather_curves_to_realize(geometry_set, info.order);
1712 info.realize_info.reinitialize(info.order.size());
1713 for (const int curve_index : info.realize_info.index_range()) {
1714 RealizeCurveInfo &curve_info = info.realize_info[curve_index];
1715 const Curves *curves_id = info.order[curve_index];
1716 const bke::CurvesGeometry &curves = curves_id->geometry.wrap();
1717 curve_info.curves = curves_id;
1718
1719 /* Access attributes. */
1720 bke::AttributeAccessor attributes = curves.attributes();
1721 curve_info.attributes.reinitialize(info.attributes.size());
1722 for (const int attribute_index : info.attributes.index_range()) {
1723 const bke::AttrDomain domain = info.attributes.kinds[attribute_index].domain;
1724 const StringRef attribute_id = info.attributes.ids[attribute_index];
1725 const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
1726 if (attributes.contains(attribute_id)) {
1727 GVArray attribute = *attributes.lookup_or_default(attribute_id, domain, data_type);
1728 curve_info.attributes[attribute_index].emplace(std::move(attribute));
1729 }
1730 }
1731 if (info.create_id_attribute) {
1732 bke::GAttributeReader id_attribute = attributes.lookup("id");
1733 if (id_attribute) {
1734 curve_info.stored_ids = id_attribute.varray.get_internal_span().typed<int>();
1735 }
1736 }
1737
1738 if (attributes.contains("radius")) {
1739 curve_info.radius =
1740 attributes.lookup<float>("radius", bke::AttrDomain::Point).varray.get_internal_span();
1741 info.create_radius_attribute = true;
1742 }
1743 if (attributes.contains("nurbs_weight")) {
1744 curve_info.nurbs_weight = attributes.lookup<float>("nurbs_weight", bke::AttrDomain::Point)
1745 .varray.get_internal_span();
1747 }
1748 curve_info.resolution = curves.resolution();
1749 if (attributes.contains("resolution")) {
1750 info.create_resolution_attribute = true;
1751 }
1752 if (attributes.contains("handle_right")) {
1753 curve_info.handle_left = attributes.lookup<float3>("handle_left", bke::AttrDomain::Point)
1754 .varray.get_internal_span();
1755 curve_info.handle_right = attributes.lookup<float3>("handle_right", bke::AttrDomain::Point)
1756 .varray.get_internal_span();
1758 }
1759 if (attributes.contains("custom_normal")) {
1760 curve_info.custom_normal = attributes.lookup<float3>("custom_normal", bke::AttrDomain::Point)
1761 .varray.get_internal_span();
1763 }
1764 }
1765 return info;
1766}
1767
1769 const AllCurvesInfo &all_curves_info,
1770 const RealizeCurveTask &task,
1771 const OrderedAttributes &ordered_attributes,
1772 bke::CurvesGeometry &dst_curves,
1773 MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
1774 MutableSpan<int> all_dst_ids,
1775 MutableSpan<float3> all_handle_left,
1776 MutableSpan<float3> all_handle_right,
1777 MutableSpan<float> all_radii,
1778 MutableSpan<float> all_nurbs_weights,
1779 MutableSpan<int> all_resolutions,
1780 MutableSpan<float3> all_custom_normals)
1781{
1782 const RealizeCurveInfo &curves_info = *task.curve_info;
1783 const Curves &curves_id = *curves_info.curves;
1784 const bke::CurvesGeometry &curves = curves_id.geometry.wrap();
1785
1786 const IndexRange dst_point_range{task.start_indices.point, curves.points_num()};
1787 const IndexRange dst_curve_range{task.start_indices.curve, curves.curves_num()};
1788
1790 curves.positions(), task.transform, dst_curves.positions_for_write().slice(dst_point_range));
1791
1792 /* Copy and transform handle positions if necessary. */
1793 if (all_curves_info.create_handle_postion_attributes) {
1794 if (curves_info.handle_left.is_empty()) {
1795 all_handle_left.slice(dst_point_range).fill(float3(0));
1796 }
1797 else {
1799 curves_info.handle_left, task.transform, all_handle_left.slice(dst_point_range));
1800 }
1801 if (curves_info.handle_right.is_empty()) {
1802 all_handle_right.slice(dst_point_range).fill(float3(0));
1803 }
1804 else {
1806 curves_info.handle_right, task.transform, all_handle_right.slice(dst_point_range));
1807 }
1808 }
1809
1810 auto copy_point_span_with_default =
1811 [&](const Span<float> src, MutableSpan<float> all_dst, const float value) {
1812 if (src.is_empty()) {
1813 all_dst.slice(dst_point_range).fill(value);
1814 }
1815 else {
1816 all_dst.slice(dst_point_range).copy_from(src);
1817 }
1818 };
1819 if (all_curves_info.create_radius_attribute) {
1820 copy_point_span_with_default(curves_info.radius, all_radii, 1.0f);
1821 }
1822 if (all_curves_info.create_nurbs_weight_attribute) {
1823 copy_point_span_with_default(curves_info.nurbs_weight, all_nurbs_weights, 1.0f);
1824 }
1825
1826 if (all_curves_info.create_resolution_attribute) {
1827 curves_info.resolution.materialize(all_resolutions.slice(dst_curve_range));
1828 }
1829
1830 if (all_curves_info.create_custom_normal_attribute) {
1831 if (curves_info.custom_normal.is_empty()) {
1832 all_custom_normals.slice(dst_point_range).fill(float3(0, 0, 1));
1833 }
1834 else {
1836 curves_info.custom_normal, task.transform, all_custom_normals.slice(dst_point_range));
1837 }
1838 }
1839
1840 /* Copy curve offsets. */
1841 const Span<int> src_offsets = curves.offsets();
1842 const MutableSpan<int> dst_offsets = dst_curves.offsets_for_write().slice(dst_curve_range);
1843 threading::parallel_for(curves.curves_range(), 2048, [&](const IndexRange range) {
1844 for (const int i : range) {
1845 dst_offsets[i] = task.start_indices.point + src_offsets[i];
1846 }
1847 });
1848
1849 if (!all_dst_ids.is_empty()) {
1850 create_result_ids(
1851 options, curves_info.stored_ids, task.id, all_dst_ids.slice(dst_point_range));
1852 }
1853
1854 copy_generic_attributes_to_result(
1855 curves_info.attributes,
1856 task.attribute_fallbacks,
1857 ordered_attributes,
1858 [&](const bke::AttrDomain domain) {
1859 switch (domain) {
1860 case bke::AttrDomain::Point:
1861 return IndexRange(task.start_indices.point, curves.points_num());
1862 case bke::AttrDomain::Curve:
1863 return IndexRange(task.start_indices.curve, curves.curves_num());
1864 default:
1865 BLI_assert_unreachable();
1866 return IndexRange();
1867 }
1868 },
1869 dst_attribute_writers);
1870}
1871
1873 const AllCurvesInfo &all_curves_info,
1874 const Span<RealizeCurveTask> tasks,
1875 const OrderedAttributes &ordered_attributes,
1876 bke::GeometrySet &r_realized_geometry)
1877{
1878 if (tasks.is_empty()) {
1879 return;
1880 }
1881
1882 if (tasks.size() == 1) {
1883 const RealizeCurveTask &task = tasks.first();
1884 Curves *new_curves = BKE_curves_copy_for_eval(task.curve_info->curves);
1885 if (!skip_transform(task.transform)) {
1886 new_curves->geometry.wrap().transform(task.transform);
1887 }
1889 task.attribute_fallbacks,
1890 new_curves->geometry.wrap().attributes_for_write());
1891 r_realized_geometry.replace_curves(new_curves);
1892 return;
1893 }
1894
1895 const RealizeCurveTask &last_task = tasks.last();
1896 const Curves &last_curves = *last_task.curve_info->curves;
1897 const int points_num = last_task.start_indices.point + last_curves.geometry.point_num;
1898 const int curves_num = last_task.start_indices.curve + last_curves.geometry.curve_num;
1899
1900 /* Allocate new curves data-block. */
1901 Curves *dst_curves_id = bke::curves_new_nomain(points_num, curves_num);
1902 bke::CurvesGeometry &dst_curves = dst_curves_id->geometry.wrap();
1903 dst_curves.offsets_for_write().last() = points_num;
1904 r_realized_geometry.replace_curves(dst_curves_id);
1905 bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
1906
1907 /* Copy settings from the first input geometry set with curves. */
1908 const RealizeCurveTask &first_task = tasks.first();
1909 const Curves &first_curves_id = *first_task.curve_info->curves;
1910 bke::curves_copy_parameters(first_curves_id, *dst_curves_id);
1911
1912 /* Prepare id attribute. */
1913 SpanAttributeWriter<int> point_ids;
1914 if (all_curves_info.create_id_attribute) {
1915 point_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id",
1916 bke::AttrDomain::Point);
1917 }
1918
1919 /* Prepare generic output attributes. */
1920 Vector<GSpanAttributeWriter> dst_attribute_writers;
1921 for (const int attribute_index : ordered_attributes.index_range()) {
1922 const StringRef attribute_id = ordered_attributes.ids[attribute_index];
1923 const bke::AttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
1924 const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
1925 dst_attribute_writers.append(
1926 dst_attributes.lookup_or_add_for_write_only_span(attribute_id, domain, data_type));
1927 }
1928
1929 /* Prepare handle position attributes if necessary. */
1930 SpanAttributeWriter<float3> handle_left;
1931 SpanAttributeWriter<float3> handle_right;
1932 if (all_curves_info.create_handle_postion_attributes) {
1933 handle_left = dst_attributes.lookup_or_add_for_write_only_span<float3>("handle_left",
1934 bke::AttrDomain::Point);
1935 handle_right = dst_attributes.lookup_or_add_for_write_only_span<float3>(
1936 "handle_right", bke::AttrDomain::Point);
1937 }
1938
1940 if (all_curves_info.create_radius_attribute) {
1941 radius = dst_attributes.lookup_or_add_for_write_only_span<float>("radius",
1942 bke::AttrDomain::Point);
1943 }
1944 SpanAttributeWriter<float> nurbs_weight;
1945 if (all_curves_info.create_nurbs_weight_attribute) {
1946 nurbs_weight = dst_attributes.lookup_or_add_for_write_only_span<float>("nurbs_weight",
1947 bke::AttrDomain::Point);
1948 }
1949 SpanAttributeWriter<int> resolution;
1950 if (all_curves_info.create_resolution_attribute) {
1951 resolution = dst_attributes.lookup_or_add_for_write_only_span<int>("resolution",
1952 bke::AttrDomain::Curve);
1953 }
1954 SpanAttributeWriter<float3> custom_normal;
1955 if (all_curves_info.create_custom_normal_attribute) {
1956 custom_normal = dst_attributes.lookup_or_add_for_write_only_span<float3>(
1957 "custom_normal", bke::AttrDomain::Point);
1958 }
1959
1960 /* Actually execute all tasks. */
1961 threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
1962 for (const int task_index : task_range) {
1963 const RealizeCurveTask &task = tasks[task_index];
1964 execute_realize_curve_task(options,
1965 all_curves_info,
1966 task,
1967 ordered_attributes,
1968 dst_curves,
1969 dst_attribute_writers,
1970 point_ids.span,
1971 handle_left.span,
1972 handle_right.span,
1973 radius.span,
1974 nurbs_weight.span,
1975 resolution.span,
1976 custom_normal.span);
1977 }
1978 });
1979
1980 /* Type counts have to be updated eagerly. */
1981 dst_curves.runtime->type_counts.fill(0);
1982 for (const RealizeCurveTask &task : tasks) {
1983 for (const int i : IndexRange(CURVE_TYPES_NUM)) {
1984 dst_curves.runtime->type_counts[i] +=
1985 task.curve_info->curves->geometry.runtime->type_counts[i];
1986 }
1987 }
1988
1989 /* Tag modified attributes. */
1990 for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
1991 dst_attribute.finish();
1992 }
1993 point_ids.finish();
1994 radius.finish();
1995 resolution.finish();
1996 nurbs_weight.finish();
1997 handle_left.finish();
1998 handle_right.finish();
1999 custom_normal.finish();
2000}
2001
2004/* -------------------------------------------------------------------- */
2009 const bke::GeometrySet &in_geometry_set,
2011 const VariedDepthOptions &varied_depth_options)
2012{
2014 in_geometry_set, bke::GeometryComponent::Type::GreasePencil, options, varied_depth_options);
2015 OrderedAttributes ordered_attributes;
2016 for (auto &&item : attributes_to_propagate.items()) {
2017 ordered_attributes.ids.add_new(item.key);
2018 ordered_attributes.kinds.append(item.value);
2019 }
2020 return ordered_attributes;
2021}
2022
2024 VectorSet<const GreasePencil *> &r_grease_pencils)
2025{
2026 if (const GreasePencil *grease_pencil = geometry_set.get_grease_pencil()) {
2027 if (!grease_pencil->layers().is_empty()) {
2028 r_grease_pencils.add(grease_pencil);
2029 }
2030 }
2031 if (const Instances *instances = geometry_set.get_instances()) {
2032 instances->foreach_referenced_geometry([&](const bke::GeometrySet &instance_geometry_set) {
2033 gather_grease_pencils_to_realize(instance_geometry_set, r_grease_pencils);
2034 });
2035 }
2036}
2037
2039 const bke::GeometrySet &geometry_set,
2041 const VariedDepthOptions &varied_depth_options)
2042{
2045 geometry_set, options, varied_depth_options);
2046
2047 gather_grease_pencils_to_realize(geometry_set, info.order);
2048 info.realize_info.reinitialize(info.order.size());
2049 for (const int grease_pencil_index : info.realize_info.index_range()) {
2050 GreasePencilRealizeInfo &grease_pencil_info = info.realize_info[grease_pencil_index];
2051 const GreasePencil *grease_pencil = info.order[grease_pencil_index];
2052 grease_pencil_info.grease_pencil = grease_pencil;
2053
2054 bke::AttributeAccessor attributes = grease_pencil->attributes();
2055 grease_pencil_info.attributes.reinitialize(info.attributes.size());
2056 for (const int attribute_index : info.attributes.index_range()) {
2057 const StringRef attribute_id = info.attributes.ids[attribute_index];
2058 const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
2059 const bke::AttrDomain domain = info.attributes.kinds[attribute_index].domain;
2060 if (attributes.contains(attribute_id)) {
2061 GVArray attribute = *attributes.lookup_or_default(attribute_id, domain, data_type);
2062 grease_pencil_info.attributes[attribute_index].emplace(std::move(attribute));
2063 }
2064 }
2065
2066 grease_pencil_info.material_index_map.reinitialize(grease_pencil->material_array_num);
2067 for (const int i : IndexRange(grease_pencil->material_array_num)) {
2068 Material *material = grease_pencil->material_array[i];
2069 grease_pencil_info.material_index_map[i] = info.materials.index_of_or_add(material);
2070 }
2071 }
2072 return info;
2073}
2074
2076 const RealizeGreasePencilTask &task,
2077 const OrderedAttributes &ordered_attributes,
2078 GreasePencil &dst_grease_pencil,
2079 MutableSpan<GSpanAttributeWriter> dst_attribute_writers)
2080{
2081 const GreasePencilRealizeInfo &grease_pencil_info = *task.grease_pencil_info;
2082 const GreasePencil &src_grease_pencil = *grease_pencil_info.grease_pencil;
2083 const Span<const bke::greasepencil::Layer *> src_layers = src_grease_pencil.layers();
2084 const IndexRange dst_layers_slice{task.start_index, src_layers.size()};
2085 const Span<bke::greasepencil::Layer *> dst_layers = dst_grease_pencil.layers_for_write().slice(
2086 dst_layers_slice);
2087
2088 for (const int layer_i : src_layers.index_range()) {
2089 const bke::greasepencil::Layer &src_layer = *src_layers[layer_i];
2090 bke::greasepencil::Layer &dst_layer = *dst_layers[layer_i];
2091 BKE_grease_pencil_copy_layer_parameters(src_layer, dst_layer);
2092
2093 dst_layer.set_name(src_layer.name());
2094 dst_layer.set_local_transform(task.transform * src_layer.local_transform());
2095
2096 const bke::greasepencil::Drawing *src_drawing = src_grease_pencil.get_eval_drawing(src_layer);
2097 if (!src_drawing) {
2098 continue;
2099 }
2100 bke::greasepencil::Drawing &dst_drawing = *dst_grease_pencil.get_eval_drawing(dst_layer);
2101
2102 const bke::CurvesGeometry &src_curves = src_drawing->strokes();
2103 bke::CurvesGeometry &dst_curves = dst_drawing.strokes_for_write();
2104 dst_curves = src_curves;
2105
2106 /* Remap materials. */
2107 bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
2108 bke::SpanAttributeWriter<int> material_indices =
2109 dst_attributes.lookup_or_add_for_write_span<int>("material_index", bke::AttrDomain::Curve);
2110 for (int &material_index : material_indices.span) {
2111 if (material_index >= 0 && material_index < src_grease_pencil.material_array_num) {
2112 material_index = grease_pencil_info.material_index_map[material_index];
2113 }
2114 }
2115 material_indices.finish();
2116 }
2117
2119 grease_pencil_info.attributes,
2120 task.attribute_fallbacks,
2121 ordered_attributes,
2122 [&](const bke::AttrDomain domain) {
2123 BLI_assert(domain == bke::AttrDomain::Layer);
2124 UNUSED_VARS_NDEBUG(domain);
2125 return dst_layers_slice;
2126 },
2127 dst_attribute_writers);
2128}
2129
2131 const float4x4 &transform)
2132{
2133 for (bke::greasepencil::Layer *layer : layers) {
2134 layer->set_local_transform(transform * layer->local_transform());
2135 }
2136}
2137
2139 const AllGreasePencilsInfo &all_grease_pencils_info,
2141 const OrderedAttributes &ordered_attributes,
2142 bke::GeometrySet &r_realized_geometry)
2143{
2144 if (tasks.is_empty()) {
2145 return;
2146 }
2147
2148 if (tasks.size() == 1) {
2149 const RealizeGreasePencilTask &task = tasks.first();
2150 GreasePencil *new_gp = BKE_grease_pencil_copy_for_eval(task.grease_pencil_info->grease_pencil);
2151 if (!skip_transform(task.transform)) {
2152 transform_grease_pencil_layers(new_gp->layers_for_write(), task.transform);
2153 }
2155 ordered_attributes, task.attribute_fallbacks, new_gp->attributes_for_write());
2156 r_realized_geometry.replace_grease_pencil(new_gp);
2157 return;
2158 }
2159
2160 const RealizeGreasePencilTask &last_task = tasks.last();
2161 const int new_layers_num = last_task.start_index +
2162 last_task.grease_pencil_info->grease_pencil->layers().size();
2163
2164 /* Allocate new grease pencil. */
2165 GreasePencil *dst_grease_pencil = BKE_grease_pencil_new_nomain();
2166 BKE_grease_pencil_copy_parameters(*tasks.first().grease_pencil_info->grease_pencil,
2167 *dst_grease_pencil);
2168 r_realized_geometry.replace_grease_pencil(dst_grease_pencil);
2169
2170 /* Allocate all layers. */
2171 dst_grease_pencil->add_layers_with_empty_drawings_for_eval(new_layers_num);
2172
2173 /* Transfer material pointers. The material indices are updated for each task separately. */
2174 if (!all_grease_pencils_info.materials.is_empty()) {
2175 MEM_SAFE_FREE(dst_grease_pencil->material_array);
2176 dst_grease_pencil->material_array_num = all_grease_pencils_info.materials.size();
2177 dst_grease_pencil->material_array = MEM_cnew_array<Material *>(
2178 dst_grease_pencil->material_array_num, __func__);
2179 uninitialized_copy_n(all_grease_pencils_info.materials.data(),
2180 dst_grease_pencil->material_array_num,
2181 dst_grease_pencil->material_array);
2182 }
2183
2184 /* Prepare generic output attributes. */
2185 bke::MutableAttributeAccessor dst_attributes = dst_grease_pencil->attributes_for_write();
2186 Vector<GSpanAttributeWriter> dst_attribute_writers;
2187 for (const int attribute_index : ordered_attributes.index_range()) {
2188 const StringRef attribute_id = ordered_attributes.ids[attribute_index];
2189 const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
2190 dst_attribute_writers.append(dst_attributes.lookup_or_add_for_write_only_span(
2191 attribute_id, bke::AttrDomain::Layer, data_type));
2192 }
2193
2194 /* Actually execute all tasks. */
2195 threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
2196 for (const int task_index : task_range) {
2197 const RealizeGreasePencilTask &task = tasks[task_index];
2198 execute_realize_grease_pencil_task(
2199 task, ordered_attributes, *dst_grease_pencil, dst_attribute_writers);
2200 }
2201 });
2202
2203 /* Tag modified attributes. */
2204 for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
2205 dst_attribute.finish();
2206 }
2207}
2208/* -------------------------------------------------------------------- */
2213 bke::GeometrySet &r_realized_geometry)
2214{
2215 if (tasks.is_empty()) {
2216 return;
2217 }
2218
2219 auto &component = r_realized_geometry.get_component_for_write<bke::GeometryComponentEditData>();
2220 for (const RealizeEditDataTask &task : tasks) {
2221 if (!component.curves_edit_hints_) {
2222 if (task.edit_data->curves_edit_hints_) {
2223 component.curves_edit_hints_ = std::make_unique<bke::CurvesEditHints>(
2224 *task.edit_data->curves_edit_hints_);
2225 }
2226 }
2227 if (const bke::GizmoEditHints *src_gizmo_edit_hints = task.edit_data->gizmo_edit_hints_.get())
2228 {
2229 if (!component.gizmo_edit_hints_) {
2230 component.gizmo_edit_hints_ = std::make_unique<bke::GizmoEditHints>();
2231 }
2232 for (auto item : src_gizmo_edit_hints->gizmo_transforms.items()) {
2233 component.gizmo_edit_hints_->gizmo_transforms.add(item.key, task.transform * item.value);
2234 }
2235 }
2236 }
2237}
2238
2241/* -------------------------------------------------------------------- */
2246{
2247 geometry_set.modify_geometry_sets([&](bke::GeometrySet &sub_geometry) {
2248 if (Instances *instances = sub_geometry.get_instances_for_write()) {
2249 instances->attributes_for_write().remove("id");
2250 }
2251 });
2252}
2253
2257static void propagate_instances_to_keep(const bke::GeometrySet &geometry_set,
2258 const IndexMask &selection,
2259 bke::GeometrySet &new_geometry_set,
2260 const bke::AttributeFilter &attribute_filter)
2261{
2262 const Instances &instances = *geometry_set.get_instances();
2263 IndexMaskMemory inverse_selection_indices;
2264 const IndexMask inverse_selection = selection.complement(IndexRange(instances.instances_num()),
2265 inverse_selection_indices);
2266 /* Check not all instances are being realized. */
2267 if (inverse_selection.is_empty()) {
2268 return;
2269 }
2270
2271 std::unique_ptr<Instances> new_instances = std::make_unique<Instances>(instances);
2272 new_instances->remove(inverse_selection, attribute_filter);
2273
2274 bke::InstancesComponent &new_instances_components =
2276 new_instances_components.replace(new_instances.release(), bke::GeometryOwnershipType::Owned);
2277}
2278
2281{
2282 if (!geometry_set.has_instances()) {
2283 return geometry_set;
2284 }
2285
2286 VariedDepthOptions all_instances;
2287 all_instances.depths = VArray<int>::ForSingle(VariedDepthOptions::MAX_DEPTH,
2288 geometry_set.get_instances()->instances_num());
2289 all_instances.selection = IndexMask(geometry_set.get_instances()->instances_num());
2290 return realize_instances(geometry_set, options, all_instances);
2291}
2292
2295 const VariedDepthOptions &varied_depth_option)
2296{
2297 /* The algorithm works in three steps:
2298 * 1. Preprocess each unique geometry that is instanced (e.g. each `Mesh`).
2299 * 2. Gather "tasks" that need to be executed to realize the instances. Each task corresponds
2300 * to instances of the previously preprocessed geometry.
2301 * 3. Execute all tasks in parallel.
2302 */
2303
2304 if (!geometry_set.has_instances()) {
2305 return geometry_set;
2306 }
2307
2308 bke::GeometrySet not_to_realize_set;
2310 geometry_set, varied_depth_option.selection, not_to_realize_set, options.attribute_filter);
2311
2312 if (options.keep_original_ids) {
2314 }
2315
2316 AllPointCloudsInfo all_pointclouds_info = preprocess_pointclouds(
2317 geometry_set, options, varied_depth_option);
2318 AllMeshesInfo all_meshes_info = preprocess_meshes(geometry_set, options, varied_depth_option);
2319 AllCurvesInfo all_curves_info = preprocess_curves(geometry_set, options, varied_depth_option);
2320 AllGreasePencilsInfo all_grease_pencils_info = preprocess_grease_pencils(
2321 geometry_set, options, varied_depth_option);
2323 geometry_set, options, varied_depth_option);
2324
2325 const bool create_id_attribute = all_pointclouds_info.create_id_attribute ||
2326 all_meshes_info.create_id_attribute ||
2327 all_curves_info.create_id_attribute;
2328 Vector<std::unique_ptr<GArray<>>> temporary_arrays;
2329 GatherTasksInfo gather_info = {all_pointclouds_info,
2330 all_meshes_info,
2331 all_curves_info,
2332 all_grease_pencils_info,
2333 all_instance_attributes,
2334 create_id_attribute,
2335 varied_depth_option.selection,
2336 varied_depth_option.depths,
2337 temporary_arrays};
2338
2339 if (not_to_realize_set.has_instances()) {
2340 gather_info.instances.instances_components_to_merge.append(
2341 not_to_realize_set.get_component_for_write<bke::InstancesComponent>().copy());
2342 gather_info.instances.instances_components_transforms.append(float4x4::identity());
2343 gather_info.instances.attribute_fallback.append(gather_info.instances_attriubutes.size());
2344 }
2345
2346 const float4x4 transform = float4x4::identity();
2347 InstanceContext attribute_fallbacks(gather_info);
2348
2350 gather_info, 0, VariedDepthOptions::MAX_DEPTH, geometry_set, transform, attribute_fallbacks);
2351
2352 bke::GeometrySet new_geometry_set;
2355 all_instance_attributes,
2356 gather_info.instances.attribute_fallback,
2357 new_geometry_set);
2358
2359 const int64_t total_points_num = get_final_points_num(gather_info.r_tasks);
2360 /* This doesn't have to be exact at all, it's just a rough estimate ot make decisions about
2361 * multi-threading (overhead). */
2362 const int64_t approximate_used_bytes_num = total_points_num * 32;
2363 threading::memory_bandwidth_bound_task(approximate_used_bytes_num, [&]() {
2365 all_pointclouds_info,
2366 gather_info.r_tasks.pointcloud_tasks,
2367 all_pointclouds_info.attributes,
2368 new_geometry_set);
2370 all_meshes_info,
2371 gather_info.r_tasks.mesh_tasks,
2372 all_meshes_info.attributes,
2373 all_meshes_info.materials,
2374 new_geometry_set);
2376 all_curves_info,
2377 gather_info.r_tasks.curve_tasks,
2378 all_curves_info.attributes,
2379 new_geometry_set);
2380 execute_realize_grease_pencil_tasks(all_grease_pencils_info,
2381 gather_info.r_tasks.grease_pencil_tasks,
2382 all_grease_pencils_info.attributes,
2383 new_geometry_set);
2384 execute_realize_edit_data_tasks(gather_info.r_tasks.edit_data_tasks, new_geometry_set);
2385 });
2386 if (gather_info.r_tasks.first_volume) {
2387 new_geometry_set.add(*gather_info.r_tasks.first_volume);
2388 }
2389
2390 return new_geometry_set;
2391}
2392
2395} // namespace blender::geometry
struct Curves * BKE_curves_copy_for_eval(const struct Curves *curves_src)
Low-level operations for curves.
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_named_layer(const CustomData *data, eCustomDataType type, blender::StringRef name)
void CustomData_set_layer_render(CustomData *data, eCustomDataType type, int n)
const char * CustomData_get_render_layer_name(const CustomData *data, eCustomDataType type)
const char * CustomData_get_active_layer_name(const CustomData *data, eCustomDataType type)
void CustomData_set_layer_active(CustomData *data, eCustomDataType type, int n)
support for deformation groups and hooks.
Low-level operations for grease pencil.
void BKE_grease_pencil_copy_parameters(const GreasePencil &src, GreasePencil &dst)
GreasePencil * BKE_grease_pencil_new_nomain()
void BKE_grease_pencil_copy_layer_parameters(const blender::bke::greasepencil::Layer &src, blender::bke::greasepencil::Layer &dst)
GreasePencil * BKE_grease_pencil_copy_for_eval(const GreasePencil *grease_pencil_src)
General operations, lookup, etc. for materials.
void BKE_id_material_eval_assign(struct ID *id, int slot, struct Material *material)
void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
Mesh * BKE_mesh_copy_for_eval(const Mesh &source)
General operations for point clouds.
PointCloud * BKE_pointcloud_copy_for_eval(const PointCloud *pointcloud_src)
PointCloud * BKE_pointcloud_new_nomain(int totpoint)
#define BLI_assert(a)
Definition BLI_assert.h:50
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
Object groups, one object can be in many groups at once.
#define CURVE_TYPES_NUM
@ CD_PROP_FLOAT2
@ CD_PROP_STRING
#define MEM_SAFE_FREE(v)
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
AttributeSet attributes
Span< T > as_span() const
Definition BLI_array.hh:232
const T & first() const
Definition BLI_array.hh:270
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:388
void fill_assign_n(const void *value, void *dst, int64_t n) const
const void * default_value() const
GMutableSpan slice(const int64_t start, int64_t size) const
const CPPType & type() const
Span< T > typed() const
const CPPType & type() const
int64_t size() const
constexpr int64_t size() const
std::optional< Value > pop_try(const Key &key)
Definition BLI_map.hh:395
bool remove(const Key &key)
Definition BLI_map.hh:344
ItemIterator items() const
Definition BLI_map.hh:864
auto add_or_modify(const Key &key, const CreateValueF &create_value, const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
Definition BLI_map.hh:457
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:574
constexpr bool is_empty() const
Definition BLI_span.hh:510
constexpr void fill(const T &value) const
Definition BLI_span.hh:518
constexpr IndexRange index_range() const
Definition BLI_span.hh:671
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:726
constexpr T & last(const int64_t n=0) const
Definition BLI_span.hh:690
bool add_as(ForwardKey &&key)
Definition BLI_set.hh:256
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr const T & first() const
Definition BLI_span.hh:316
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr const T & last(const int64_t n=0) const
Definition BLI_span.hh:326
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
constexpr bool is_empty() const
Definition BLI_span.hh:261
std::optional< T > get_if_single() const
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
const Key * data() const
const Key * begin() const
const Key * end() const
int64_t index_of_or_add(const Key &key)
int64_t size() const
void append(const T &value)
IndexRange index_range() const
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
GAttributeReader get() const
MutableSpan< float3 > positions_for_write()
MutableAttributeAccessor attributes_for_write()
MutableSpan< int > offsets_for_write()
void convert_to_initialized_n(GSpan from_span, GMutableSpan to_span) const
bool is_convertible(const CPPType &from_type, const CPPType &to_type) const
std::unique_ptr< CurvesEditHints > curves_edit_hints_
int attribute_domain_size(AttrDomain domain) const
GeometryComponentPtr copy() const override
void replace(Instances *instances, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
Span< int > reference_handles() const
Definition instances.cc:207
Span< float4x4 > transforms() const
Definition instances.cc:225
Span< InstanceReference > references() const
Definition instances.cc:277
int instances_num() const
Definition instances.cc:390
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type)
bke::CurvesGeometry & strokes_for_write()
const bke::CurvesGeometry & strokes() const
void set_local_transform(const float4x4 &transform)
IndexMask complement(const IndexMask &universe, IndexMaskMemory &memory) const
void foreach_index(Fn &&fn) const
CCL_NAMESPACE_BEGIN struct Options options
static void transform_positions(const Span< blender::float3 > src, const blender::float4x4 &transform, blender::MutableSpan< blender::float3 > dst)
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
struct blender::compositor::@172::@174 task
static void propagate_instances_to_keep(const bke::GeometrySet &geometry_set, const IndexMask &selection, bke::GeometrySet &new_geometry_set, const bke::AttributeFilter &attribute_filter)
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, bke::GeometrySet &r_realized_geometry)
static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info, const int current_depth, const int target_depth, const bke::GeometrySet &geometry_set, const float4x4 &base_transform, const InstanceContext &base_instance_context)
static OrderedAttributes gather_generic_pointcloud_attributes_to_propagate(const bke::GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, const VariedDepthOptions &varied_depth_option, bool &r_create_radii, bool &r_create_id)
static void execute_instances_tasks(const Span< bke::GeometryComponentPtr > src_components, Span< blender::float4x4 > src_base_transforms, OrderedAttributes all_instances_attributes, Span< blender::geometry::AttributeFallbacksArray > attribute_fallback, bke::GeometrySet &r_realized_geometry)
static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &options, const AllPointCloudsInfo &all_pointclouds_info, const Span< RealizePointCloudTask > tasks, const OrderedAttributes &ordered_attributes, bke::GeometrySet &r_realized_geometry)
static void threaded_copy(const GSpan src, GMutableSpan dst)
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< float > all_nurbs_weights, MutableSpan< int > all_resolutions, MutableSpan< float3 > all_custom_normals)
static AllMeshesInfo preprocess_meshes(const bke::GeometrySet &geometry_set, const RealizeInstancesOptions &options, const VariedDepthOptions &varied_depth_option)
static void gather_grease_pencils_to_realize(const bke::GeometrySet &geometry_set, VectorSet< const GreasePencil * > &r_grease_pencils)
static void execute_realize_pointcloud_task(const RealizeInstancesOptions &options, const RealizePointCloudTask &task, const OrderedAttributes &ordered_attributes, MutableSpan< GSpanAttributeWriter > dst_attribute_writers, MutableSpan< float > all_dst_radii, MutableSpan< int > all_dst_ids, MutableSpan< float3 > all_dst_positions)
static int64_t get_final_points_num(const GatherTasks &tasks)
static void gather_pointclouds_to_realize(const bke::GeometrySet &geometry_set, VectorSet< const PointCloud * > &r_pointclouds)
static void execute_realize_grease_pencil_task(const RealizeGreasePencilTask &task, const OrderedAttributes &ordered_attributes, GreasePencil &dst_grease_pencil, MutableSpan< GSpanAttributeWriter > dst_attribute_writers)
static void execute_realize_curve_tasks(const RealizeInstancesOptions &options, const AllCurvesInfo &all_curves_info, const Span< RealizeCurveTask > tasks, const OrderedAttributes &ordered_attributes, bke::GeometrySet &r_realized_geometry)
static OrderedAttributes gather_generic_curve_attributes_to_propagate(const bke::GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, const VariedDepthOptions &varied_depth_option, bool &r_create_id)
static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info, const int current_depth, const int target_depth, const Instances &instances, const float4x4 &base_transform, const InstanceContext &base_instance_context)
static void remove_id_attribute_from_instances(bke::GeometrySet &geometry_set)
static void create_result_ids(const RealizeInstancesOptions &options, const Span< int > stored_ids, const int task_id, MutableSpan< int > dst_ids)
static void gather_curves_to_realize(const bke::GeometrySet &geometry_set, VectorSet< const Curves * > &r_curves)
static void transform_grease_pencil_layers(Span< bke::greasepencil::Layer * > layers, const float4x4 &transform)
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(bke::AttrDomain)> &range_fn, MutableSpan< GSpanAttributeWriter > dst_attribute_writers)
void join_attributes(const Span< const bke::GeometryComponent * > src_components, bke::GeometryComponent &r_result, const Span< StringRef > ignored_attributes={})
static void copy_transformed_normals(const Span< float3 > src, const float4x4 &transform, MutableSpan< float3 > dst)
static void gather_attribute_propagation_components_with_custom_depths(const bke::GeometrySet &geometry, const bke::GeometryComponent::Type component_type, const RealizeInstancesOptions &options, const VariedDepthOptions &varied_depth_option, Set< bke::GeometryComponentPtr > &r_components)
static Vector< std::pair< int, GSpan > > prepare_attribute_fallbacks(GatherTasksInfo &gather_info, const Instances &instances, const OrderedAttributes &ordered_attributes)
static AllPointCloudsInfo preprocess_pointclouds(const bke::GeometrySet &geometry_set, const RealizeInstancesOptions &options, const VariedDepthOptions &varied_depth_option)
static void execute_realize_mesh_task(const RealizeInstancesOptions &options, const RealizeMeshTask &task, const OrderedAttributes &ordered_attributes, MutableSpan< GSpanAttributeWriter > dst_attribute_writers, MutableSpan< float3 > all_dst_positions, MutableSpan< int2 > all_dst_edges, MutableSpan< int > all_dst_face_offsets, MutableSpan< int > all_dst_corner_verts, MutableSpan< int > all_dst_corner_edges, MutableSpan< int > all_dst_vertex_ids, MutableSpan< int > all_dst_material_indices)
static Map< StringRef, AttributeKind > gather_attributes_to_propagate(const bke::GeometrySet &geometry, const bke::GeometryComponent::Type component_type, const RealizeInstancesOptions &options, const VariedDepthOptions &varied_depth_option)
static AllCurvesInfo preprocess_curves(const bke::GeometrySet &geometry_set, const RealizeInstancesOptions &options, const VariedDepthOptions &varied_depth_option)
static void gather_meshes_to_realize(const bke::GeometrySet &geometry_set, VectorSet< const Mesh * > &r_meshes)
static void add_instance_attributes_to_single_geometry(const OrderedAttributes &ordered_attributes, const AttributeFallbacksArray &attribute_fallbacks, bke::MutableAttributeAccessor attributes)
static AllGreasePencilsInfo preprocess_grease_pencils(const bke::GeometrySet &geometry_set, const RealizeInstancesOptions &options, const VariedDepthOptions &varied_depth_options)
static OrderedAttributes gather_generic_instance_attributes_to_propagate(const bke::GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, const VariedDepthOptions &varied_depth_option)
static void foreach_geometry_in_reference(const InstanceReference &reference, const float4x4 &base_transform, const uint32_t id, FunctionRef< void(const bke::GeometrySet &geometry_set, const float4x4 &transform, uint32_t id)> fn)
static void threaded_fill(const GPointer value, GMutableSpan dst)
static void execute_realize_edit_data_tasks(const Span< RealizeEditDataTask > tasks, bke::GeometrySet &r_realized_geometry)
static bool skip_transform(const float4x4 &transform)
static OrderedAttributes gather_generic_grease_pencil_attributes_to_propagate(const bke::GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, const VariedDepthOptions &varied_depth_options)
bke::GeometrySet realize_instances(bke::GeometrySet geometry_set, const RealizeInstancesOptions &options)
static void gather_attribute_propagation_components(const bke::GeometrySet &geometry, const bke::GeometryComponent::Type component_type, const RealizeInstancesOptions &options, const int current_depth, const std::optional< int > max_depth, Set< bke::GeometryComponentPtr > &r_components)
static void execute_realize_grease_pencil_tasks(const AllGreasePencilsInfo &all_grease_pencils_info, const Span< RealizeGreasePencilTask > tasks, const OrderedAttributes &ordered_attributes, bke::GeometrySet &r_realized_geometry)
static void copy_transformed_positions(const Span< float3 > src, const float4x4 &transform, MutableSpan< float3 > dst)
static OrderedAttributes gather_generic_mesh_attributes_to_propagate(const bke::GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, const VariedDepthOptions &varied_depth_option, bool &r_create_id, bool &r_create_material_index)
MatBase< T, NumCol, NumRow > transpose(const MatBase< T, NumRow, NumCol > &mat)
CartesianBasis invert(const CartesianBasis &basis)
bool is_equal(const MatBase< T, NumCol, NumRow > &a, const MatBase< T, NumCol, NumRow > &b, const T epsilon=T(0))
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:95
void uninitialized_copy_n(const T *src, int64_t n, T *dst)
unsigned int uint32_t
Definition stdint.h:80
__int64 int64_t
Definition stdint.h:89
CurvesGeometry geometry
struct Material ** material_array
int corners_num
int edges_num
CustomData corner_data
ListBase vertex_group_names
int faces_num
int verts_num
struct Material ** mat
bool allow_skip(const StringRef name) const
GeometryComponent & get_component_for_write(GeometryComponent::Type component_type)
void replace_instances(Instances *instances, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
Instances * get_instances_for_write()
const GreasePencil * get_grease_pencil() const
Vector< const GeometryComponent * > get_components() const
void replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
const Curves * get_curves() const
const Instances * get_instances() const
void replace_curves(Curves *curves, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
const PointCloud * get_pointcloud() const
const Mesh * get_mesh() const
void modify_geometry_sets(ForeachSubGeometryCallback callback)
void replace_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
void add(const GeometryComponent &component)
void replace_grease_pencil(GreasePencil *grease_pencil, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
VectorSet< const Curves * > order
Array< RealizeCurveInfo > realize_info
VectorSet< const GreasePencil * > order
Array< GreasePencilRealizeInfo > realize_info
Vector< AttributeFallbacksArray > attribute_fallback
Vector< bke::GeometryComponentPtr > instances_components_to_merge
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
const OrderedAttributes & instances_attriubutes
const AllGreasePencilsInfo & grease_pencils
Vector< RealizeMeshTask > mesh_tasks
Vector< RealizeEditDataTask > edit_data_tasks
Vector< RealizePointCloudTask > pointcloud_tasks
Vector< RealizeCurveTask > curve_tasks
ImplicitSharingPtr< const bke::VolumeComponent > first_volume
Vector< RealizeGreasePencilTask > grease_pencil_tasks
Array< std::optional< GVArraySpan > > attributes
InstanceContext(const GatherTasksInfo &gather_info)
Array< std::optional< GVArraySpan > > attributes
Array< std::optional< GVArraySpan > > attributes
Array< std::optional< GVArraySpan > > attributes
AttributeFallbacksArray attribute_fallbacks
CurvesElementStartIndices start_indices
const bke::GeometryComponentEditData * edit_data
const GreasePencilRealizeInfo * grease_pencil_info
AttributeFallbacksArray attribute_fallbacks
const PointCloudRealizeInfo * pointcloud_info