Blender V5.0
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
8#include "DNA_object_types.h"
9
10#include "BLI_array_utils.hh"
11#include "BLI_listbase.h"
12#include "BLI_math_matrix.hh"
13#include "BLI_noise.hh"
14
15#include "BKE_attribute.hh"
16#include "BKE_curves.hh"
17#include "BKE_customdata.hh"
19#include "BKE_grease_pencil.hh"
20#include "BKE_instances.hh"
21#include "BKE_material.hh"
22#include "BKE_mesh.hh"
23#include "BKE_pointcloud.hh"
25
26#include "BLT_translation.hh"
27
28namespace blender::geometry {
29
31using blender::bke::AttributeDomainAndType;
32using blender::bke::GSpanAttributeWriter;
33using blender::bke::InstanceReference;
34using blender::bke::Instances;
35using blender::bke::SpanAttributeWriter;
36
44
45 int size() const
46 {
47 return this->kinds.size();
48 }
49
51 {
52 return this->kinds.index_range();
53 }
54};
55
67
77
89
92 int vertex = 0;
93 int edge = 0;
94 int face = 0;
95 int loop = 0;
96};
97
116
126
166
169 int point = 0;
170 int curve = 0;
171 int custom_knot = 0;
172};
173
184
192
200
205
216
235
248
259
268
281
298
329
345 uint32_t id = 0;
346
348 : pointclouds(gather_info.pointclouds.attributes.size()),
349 meshes(gather_info.meshes.attributes.size()),
350 curves(gather_info.curves.attributes.size()),
351 grease_pencils(gather_info.grease_pencils.attributes.size()),
352 instances(gather_info.instances_attriubutes.size())
353 {
354 // empty
355 }
356};
357
358static bool valid_int_num(const int64_t num)
359{
360 return num >= 0 && num <= INT32_MAX;
361}
362
364{
365 int64_t points_num = 0;
366 if (!tasks.pointcloud_tasks.is_empty()) {
367 const RealizePointCloudTask &task = tasks.pointcloud_tasks.last();
368 points_num += task.start_index + task.pointcloud_info->pointcloud->totpoint;
369 }
370 if (!tasks.mesh_tasks.is_empty()) {
371 const RealizeMeshTask &task = tasks.mesh_tasks.last();
372 points_num += task.start_indices.vertex + task.mesh_info->mesh->verts_num;
373 }
374 if (!tasks.curve_tasks.is_empty()) {
375 const RealizeCurveTask &task = tasks.curve_tasks.last();
376 points_num += task.start_indices.point + task.curve_info->curves->geometry.point_num;
377 }
378 return points_num;
379}
380
382{
384}
385
386static void threaded_copy(const GSpan src, GMutableSpan dst)
387{
388 BLI_assert(src.size() == dst.size());
389 BLI_assert(src.type() == dst.type());
390 threading::parallel_for(IndexRange(src.size()), 1024, [&](const IndexRange range) {
391 src.type().copy_construct_n(src.slice(range).data(), dst.slice(range).data(), range.size());
392 });
393}
394
395static void threaded_fill(const GPointer value, GMutableSpan dst)
396{
397 BLI_assert(*value.type() == dst.type());
398 threading::parallel_for(IndexRange(dst.size()), 1024, [&](const IndexRange range) {
399 value.type()->fill_construct_n(value.get(), dst.slice(range).data(), range.size());
400 });
401}
402
404 const Span<std::optional<GVArraySpan>> src_attributes,
405 const AttributeFallbacksArray &attribute_fallbacks,
406 const OrderedAttributes &ordered_attributes,
407 const FunctionRef<IndexRange(bke::AttrDomain)> &range_fn,
408 MutableSpan<GSpanAttributeWriter> dst_attribute_writers)
409{
411 dst_attribute_writers.index_range(), 10, [&](const IndexRange attribute_range) {
412 for (const int attribute_index : attribute_range) {
413 const bke::AttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
414 const IndexRange element_slice = range_fn(domain);
415
416 GSpanAttributeWriter &writer = dst_attribute_writers[attribute_index];
417 if (!writer) {
418 continue;
419 }
420 GMutableSpan dst_span = writer.span.slice(element_slice);
421 if (src_attributes[attribute_index].has_value()) {
422 threaded_copy(*src_attributes[attribute_index], dst_span);
423 }
424 else {
425 const CPPType &cpp_type = dst_span.type();
426 const void *fallback = attribute_fallbacks.array[attribute_index] == nullptr ?
427 cpp_type.default_value() :
428 attribute_fallbacks.array[attribute_index];
429 threaded_fill({cpp_type, fallback}, dst_span);
430 }
431 }
432 });
433}
434
436 const Span<int> stored_ids,
437 const int task_id,
438 MutableSpan<int> dst_ids)
439{
440 if (options.keep_original_ids) {
441 if (stored_ids.is_empty()) {
442 dst_ids.fill(0);
443 }
444 else {
445 dst_ids.copy_from(stored_ids);
446 }
447 }
448 else {
449 if (stored_ids.is_empty()) {
450 threading::parallel_for(dst_ids.index_range(), 1024, [&](const IndexRange range) {
451 for (const int i : range) {
452 dst_ids[i] = noise::hash(task_id, i);
453 }
454 });
455 }
456 else {
457 threading::parallel_for(dst_ids.index_range(), 1024, [&](const IndexRange range) {
458 for (const int i : range) {
459 dst_ids[i] = noise::hash(task_id, stored_ids[i]);
460 }
461 });
462 }
463 }
464}
465
466/* -------------------------------------------------------------------- */
469
470/* Forward declaration. */
471static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
472 const int current_depth,
473 const int target_depth,
474 const bke::GeometrySet &geometry_set,
475 const float4x4 &base_transform,
476 const InstanceContext &base_instance_context);
477
484 GatherTasksInfo &gather_info,
485 const Instances &instances,
486 const OrderedAttributes &ordered_attributes)
487{
488 Vector<std::pair<int, GSpan>> attributes_to_override;
489 const bke::AttributeAccessor attributes = instances.attributes();
490 attributes.foreach_attribute([&](const bke::AttributeIter &iter) {
491 const int attribute_index = ordered_attributes.ids.index_of_try(iter.name);
492 if (attribute_index == -1) {
493 /* The attribute is not propagated to the final geometry. */
494 return;
495 }
496 const bke::GAttributeReader attribute = iter.get();
497 if (!attribute || !attribute.varray.is_span()) {
498 return;
499 }
500 GSpan span = attribute.varray.get_internal_span();
501 const bke::AttrType expected_type = ordered_attributes.kinds[attribute_index].data_type;
502 if (iter.data_type != expected_type) {
503 const CPPType &from_type = span.type();
504 const CPPType &to_type = bke::attribute_type_to_cpp_type(expected_type);
506 if (!conversions.is_convertible(from_type, to_type)) {
507 /* Ignore the attribute because it can not be converted to the desired type. */
508 return;
509 }
510 /* Convert the attribute on the instances component to the expected attribute type. */
511 std::unique_ptr<GArray<>> temporary_array = std::make_unique<GArray<>>(
512 to_type, instances.instances_num());
513 conversions.convert_to_initialized_n(span, temporary_array->as_mutable_span());
514 span = temporary_array->as_span();
515 gather_info.r_temporary_arrays.append(std::move(temporary_array));
516 }
517 attributes_to_override.append({attribute_index, span});
518 });
519 return attributes_to_override;
520}
521
527 const InstanceReference &reference,
528 const float4x4 &base_transform,
529 const uint32_t id,
530 FunctionRef<void(const bke::GeometrySet &geometry_set, const float4x4 &transform, uint32_t id)>
531 fn)
532{
533 bke::GeometrySet geometry_set;
534 reference.to_geometry_set(geometry_set);
535 fn(geometry_set, base_transform, id);
536}
537
539 const int current_depth,
540 const int target_depth,
541 const Instances &instances,
542 const float4x4 &base_transform,
543 const InstanceContext &base_instance_context)
544{
545 const Span<InstanceReference> references = instances.references();
546 const Span<int> handles = instances.reference_handles();
547 const Span<float4x4> transforms = instances.transforms();
548
549 Span<int> stored_instance_ids;
550 if (gather_info.create_id_attribute_on_any_component) {
551 bke::GAttributeReader ids = instances.attributes().lookup("id");
552 if (ids && ids.domain == bke::AttrDomain::Instance && ids.varray.type().is<int>() &&
553 ids.varray.is_span())
554 {
555 stored_instance_ids = ids.varray.get_internal_span().typed<int>();
556 }
557 }
558
559 /* Prepare attribute fallbacks. */
560 InstanceContext instance_context = base_instance_context;
561 Vector<std::pair<int, GSpan>> pointcloud_attributes_to_override = prepare_attribute_fallbacks(
562 gather_info, instances, gather_info.pointclouds.attributes);
563 Vector<std::pair<int, GSpan>> mesh_attributes_to_override = prepare_attribute_fallbacks(
564 gather_info, instances, gather_info.meshes.attributes);
565 Vector<std::pair<int, GSpan>> curve_attributes_to_override = prepare_attribute_fallbacks(
566 gather_info, instances, gather_info.curves.attributes);
567 Vector<std::pair<int, GSpan>> grease_pencil_attributes_to_override = prepare_attribute_fallbacks(
568 gather_info, instances, gather_info.grease_pencils.attributes);
569 Vector<std::pair<int, GSpan>> instance_attributes_to_override = prepare_attribute_fallbacks(
570 gather_info, instances, gather_info.instances_attriubutes);
571
572 const bool is_top_level = current_depth == 0;
573 /* If at top level, get instance indices from selection field, else use all instances. */
574 const IndexMask indices = is_top_level ? gather_info.selection :
575 IndexMask(IndexRange(instances.instances_num()));
576 indices.foreach_index([&](const int i) {
577 /* If at top level, retrieve depth from gather_info, else continue with target_depth. */
578 const int child_target_depth = is_top_level ? gather_info.depths[i] : target_depth;
579 const int handle = handles[i];
580 const float4x4 &transform = transforms[i];
581 const InstanceReference &reference = references[handle];
582 const float4x4 new_base_transform = base_transform * transform;
583
584 /* Update attribute fallbacks for the current instance. */
585 for (const std::pair<int, GSpan> &pair : pointcloud_attributes_to_override) {
586 instance_context.pointclouds.array[pair.first] = pair.second[i];
587 }
588 for (const std::pair<int, GSpan> &pair : mesh_attributes_to_override) {
589 instance_context.meshes.array[pair.first] = pair.second[i];
590 }
591 for (const std::pair<int, GSpan> &pair : curve_attributes_to_override) {
592 instance_context.curves.array[pair.first] = pair.second[i];
593 }
594 for (const std::pair<int, GSpan> &pair : grease_pencil_attributes_to_override) {
595 instance_context.grease_pencils.array[pair.first] = pair.second[i];
596 }
597 for (const std::pair<int, GSpan> &pair : instance_attributes_to_override) {
598 instance_context.instances.array[pair.first] = pair.second[i];
599 }
600
601 uint32_t local_instance_id = 0;
602 if (gather_info.create_id_attribute_on_any_component) {
603 if (stored_instance_ids.is_empty()) {
604 local_instance_id = uint32_t(i);
605 }
606 else {
607 local_instance_id = uint32_t(stored_instance_ids[i]);
608 }
609 }
610 const uint32_t instance_id = noise::hash(base_instance_context.id, local_instance_id);
611
612 /* Add realize tasks for all referenced geometry sets recursively. */
614 new_base_transform,
615 instance_id,
616 [&](const bke::GeometrySet &instance_geometry_set,
617 const float4x4 &transform,
618 const uint32_t id) {
619 instance_context.id = id;
621 current_depth + 1,
622 child_target_depth,
623 instance_geometry_set,
624 transform,
625 instance_context);
626 });
627 });
628}
629
634 const int current_depth,
635 const int target_depth,
636 const bke::GeometrySet &geometry_set,
637 const float4x4 &base_transform,
638 const InstanceContext &base_instance_context)
639{
640 for (const bke::GeometryComponent *component : geometry_set.get_components()) {
641 const bke::GeometryComponent::Type type = component->type();
642 switch (type) {
644 const Mesh *mesh = (*static_cast<const bke::MeshComponent *>(component)).get();
645 if (mesh != nullptr && mesh->verts_num > 0) {
646 const int mesh_index = gather_info.meshes.order.index_of(mesh);
647 const MeshRealizeInfo &mesh_info = gather_info.meshes.realize_info[mesh_index];
648 gather_info.r_tasks.mesh_tasks.append({{int(gather_info.r_offsets.mesh_offsets.vertex),
649 int(gather_info.r_offsets.mesh_offsets.edge),
650 int(gather_info.r_offsets.mesh_offsets.face),
651 int(gather_info.r_offsets.mesh_offsets.corner)},
652 &mesh_info,
653 base_transform,
654 base_instance_context.meshes,
655 base_instance_context.id});
656 gather_info.r_offsets.mesh_offsets.vertex += mesh->verts_num;
657 gather_info.r_offsets.mesh_offsets.edge += mesh->edges_num;
658 gather_info.r_offsets.mesh_offsets.corner += mesh->corners_num;
659 gather_info.r_offsets.mesh_offsets.face += mesh->faces_num;
660 }
661 break;
662 }
664 const auto &pointcloud_component = *static_cast<const bke::PointCloudComponent *>(
665 component);
666 const PointCloud *pointcloud = pointcloud_component.get();
667 if (pointcloud != nullptr && pointcloud->totpoint > 0) {
668 const int pointcloud_index = gather_info.pointclouds.order.index_of(pointcloud);
669 const PointCloudRealizeInfo &pointcloud_info =
670 gather_info.pointclouds.realize_info[pointcloud_index];
671 gather_info.r_tasks.pointcloud_tasks.append(
672 {int(gather_info.r_offsets.pointcloud_offset),
673 &pointcloud_info,
674 base_transform,
675 base_instance_context.pointclouds,
676 base_instance_context.id});
677 gather_info.r_offsets.pointcloud_offset += pointcloud->totpoint;
678 }
679 break;
680 }
682 const auto &curve_component = *static_cast<const bke::CurveComponent *>(component);
683 const Curves *curves = curve_component.get();
684 if (curves != nullptr && curves->geometry.curve_num > 0) {
685 const int curve_index = gather_info.curves.order.index_of(curves);
686 const RealizeCurveInfo &curve_info = gather_info.curves.realize_info[curve_index];
687 gather_info.r_tasks.curve_tasks.append(
688 {{int(gather_info.r_offsets.curves_offsets.point),
689 int(gather_info.r_offsets.curves_offsets.curve),
690 int(gather_info.r_offsets.curves_offsets.custom_knot)},
691 &curve_info,
692 base_transform,
693 base_instance_context.curves,
694 base_instance_context.id});
695 gather_info.r_offsets.curves_offsets.point += curves->geometry.point_num;
696 gather_info.r_offsets.curves_offsets.curve += curves->geometry.curve_num;
698 }
699 break;
700 }
702 const auto &grease_pencil_component = *static_cast<const bke::GreasePencilComponent *>(
703 component);
704 const GreasePencil *grease_pencil = grease_pencil_component.get();
705 if (grease_pencil != nullptr && !grease_pencil->layers().is_empty()) {
706 const int grease_pencil_index = gather_info.grease_pencils.order.index_of(grease_pencil);
707 const GreasePencilRealizeInfo &grease_pencil_info =
708 gather_info.grease_pencils.realize_info[grease_pencil_index];
709 gather_info.r_tasks.grease_pencil_tasks.append(
710 {int(gather_info.r_offsets.grease_pencil_layer_offset),
711 &grease_pencil_info,
712 base_transform,
713 base_instance_context.grease_pencils});
714 gather_info.r_offsets.grease_pencil_layer_offset += grease_pencil->layers().size();
715 }
716 break;
717 }
719 if (current_depth == target_depth) {
720 gather_info.instances.attribute_fallback.append(base_instance_context.instances);
721 gather_info.instances.instances_components_to_merge.append(component->copy());
722 gather_info.instances.instances_components_transforms.append(base_transform);
723 }
724 else {
725 const Instances *instances =
726 (*static_cast<const bke::InstancesComponent *>(component)).get();
727 if (instances != nullptr && instances->instances_num() > 0) {
729 current_depth,
730 target_depth,
731 *instances,
732 base_transform,
733 base_instance_context);
734 }
735 }
736 break;
737 }
739 if (!gather_info.r_tasks.first_volume) {
740 const bke::VolumeComponent *volume_component = static_cast<const bke::VolumeComponent *>(
741 component);
742 volume_component->add_user();
744 volume_component);
745 }
746 break;
747 }
749 const auto *edit_component = static_cast<const bke::GeometryComponentEditData *>(
750 component);
751 if (edit_component->gizmo_edit_hints_ || edit_component->curves_edit_hints_) {
752 gather_info.r_tasks.edit_data_tasks.append({edit_component, base_transform});
753 }
754 break;
755 }
756 }
757 }
758}
759
762 const bke::GeometryComponent::Type component_type,
764 const int current_depth,
765 const std::optional<int> max_depth,
766 Set<bke::GeometryComponentPtr> &r_components)
767{
768 if (const bke::GeometryComponent *component = geometry.get_component(component_type)) {
769 if (r_components.add_as(component)) {
770 component->add_user();
771 }
772 }
773 if (current_depth == max_depth) {
774 return;
775 }
776 const auto *instances_component = geometry.get_component<bke::InstancesComponent>();
777 if (!instances_component) {
778 return;
779 }
780 const bke::Instances *instances = instances_component->get();
781 if (!instances) {
782 return;
783 }
784 if (options.realize_instance_attributes) {
785 if (r_components.add_as(instances_component)) {
786 instances_component->add_user();
787 }
788 }
789 for (const bke::InstanceReference &reference : instances->references()) {
790 bke::GeometrySet reference_geometry;
791 reference.to_geometry_set(reference_geometry);
793 reference_geometry, component_type, options, current_depth + 1, max_depth, r_components);
794 }
795}
796
799 const bke::GeometryComponent::Type component_type,
801 const VariedDepthOptions &varied_depth_option,
802 Set<bke::GeometryComponentPtr> &r_components)
803{
804 if (const bke::GeometryComponent *component = geometry.get_component(component_type)) {
805 if (r_components.add_as(component)) {
806 component->add_user();
807 }
808 }
809 const auto *instances_component = geometry.get_component<bke::InstancesComponent>();
810 if (!instances_component) {
811 return;
812 }
813 const bke::Instances *instances = instances_component->get();
814 if (!instances) {
815 return;
816 }
817
818 const Span<bke::InstanceReference> references = instances->references();
819 const Span<int> handles = instances->reference_handles();
820 const int references_num = references.size();
821 Array<std::optional<int>> max_reference_depth(references_num, 0);
822
823 varied_depth_option.selection.foreach_index([&](const int instance_i) {
824 const int reference_i = handles[instance_i];
825 const int instance_depth = varied_depth_option.depths[instance_i];
826 std::optional<int> &max_depth = max_reference_depth[reference_i];
827 if (!max_depth.has_value()) {
828 /* Is already at max depth. */
829 return;
830 }
831 if (instance_depth == VariedDepthOptions::MAX_DEPTH) {
832 max_depth.reset();
833 return;
834 }
835 max_depth = std::max<int>(*max_depth, instance_depth);
836 });
837
838 bool is_anything_realized = false;
839 for (const int reference_i : IndexRange(references_num)) {
840 const std::optional<int> max_depth = max_reference_depth[reference_i];
841 if (max_depth == 0) {
842 continue;
843 }
844 const bke::InstanceReference &reference = references[reference_i];
845 bke::GeometrySet reference_geometry;
846 reference.to_geometry_set(reference_geometry);
848 reference_geometry, component_type, options, 1, max_depth, r_components);
849 is_anything_realized = true;
850 }
851
852 if (is_anything_realized) {
853 if (options.realize_instance_attributes) {
854 if (r_components.add_as(instances_component)) {
855 instances_component->add_user();
856 }
857 }
858 }
859}
860
863 const bke::GeometryComponent::Type component_type,
865 const VariedDepthOptions &varied_depth_option)
866{
867 const bke::AttributeFilter &attribute_filter = options.attribute_filter;
868
869 const bke::InstancesComponent *top_level_instances_component =
870 geometry.get_component<bke::InstancesComponent>();
871 const int top_level_instances_num = top_level_instances_component ?
872 top_level_instances_component->attribute_domain_size(
873 AttrDomain::Instance) :
874 0;
875
876 /* Needs to take ownership because some components are only temporary otherwise. */
878 if (varied_depth_option.depths.get_if_single() == VariedDepthOptions::MAX_DEPTH &&
879 varied_depth_option.selection.size() == top_level_instances_num)
880 {
881 /* In this case we don't have to iterate over all instances, just over the references. */
883 geometry, component_type, options, 0, std::nullopt, components);
884 }
885 else {
887 geometry, component_type, options, varied_depth_option, components);
888 }
889
890 /* Actually gather the attributes to propagate from the found components. */
891 bke::GeometrySet::GatheredAttributes attributes_to_propagate;
892 for (const bke::GeometryComponentPtr &component : components) {
893 const bke::AttributeAccessor attributes = *component->attributes();
894 attributes.foreach_attribute([&](const bke::AttributeIter &iter) {
895 if (iter.is_builtin) {
896 if (!bke::attribute_is_builtin_on_component_type(component_type, iter.name)) {
897 /* Don't propagate built-in attributes that are not built-in on the
898 * destination component. */
899 return;
900 }
901 }
902 if (component->type() == bke::GeometryComponent::Type::Instance) {
903 if (ELEM(iter.name, "instance_transform", ".reference_index")) {
904 /* These attributes reference potentially temporary instance components in the set above.
905 * If we added these names, the string references in the result map would outlive the
906 * attributes they reference. */
907 return;
908 }
909 }
910 if (iter.data_type == bke::AttrType::String) {
911 /* Propagating string attributes is not supported yet. */
912 return;
913 }
914 if (attribute_filter.allow_skip(iter.name)) {
915 return;
916 }
917 AttrDomain dst_domain = iter.domain;
918 if (component_type != bke::GeometryComponent::Type::Instance &&
919 dst_domain == AttrDomain::Instance)
920 {
921 if (component_type == bke::GeometryComponent::Type::GreasePencil) {
922 /* For Grease Pencil, we want to propagate the instance attributes to the layers. */
923 dst_domain = AttrDomain::Layer;
924 }
925 else {
926 /* Other instance attributes are realized on the point domain currently. */
927 dst_domain = AttrDomain::Point;
928 }
929 }
930 attributes_to_propagate.add(iter.name, AttributeDomainAndType{dst_domain, iter.data_type});
931 });
932 }
933
934 return attributes_to_propagate;
935}
936
938
939/* -------------------------------------------------------------------- */
942
944 const bke::GeometrySet &in_geometry_set,
946 const VariedDepthOptions &varied_depth_option)
947{
949 in_geometry_set, bke::GeometryComponent::Type::Instance, options, varied_depth_option);
950 OrderedAttributes ordered_attributes;
951 for (const int i : attributes_to_propagate.names.index_range()) {
952 if (attributes_to_propagate.names[i] == "id") {
953 continue;
954 }
955 ordered_attributes.ids.add_new(attributes_to_propagate.names[i]);
956 ordered_attributes.kinds.append(attributes_to_propagate.kinds[i]);
957 }
958 return ordered_attributes;
959}
960
962 const Span<bke::GeometryComponentPtr> src_components,
963 const Span<blender::float4x4> src_base_transforms,
964 const OrderedAttributes &all_instances_attributes,
966 bke::GeometrySet &r_realized_geometry)
967{
968 BLI_assert(src_components.size() == src_base_transforms.size() &&
969 src_components.size() == attribute_fallback.size());
970 if (src_components.is_empty()) {
971 return;
972 }
973
974 Array<int> offsets_data(src_components.size() + 1);
975 for (const int component_index : src_components.index_range()) {
976 const bke::InstancesComponent &src_component = static_cast<const bke::InstancesComponent &>(
977 *src_components[component_index]);
978 offsets_data[component_index] = src_component.get()->instances_num();
979 }
981
982 std::unique_ptr<bke::Instances> dst_instances = std::make_unique<bke::Instances>();
983 dst_instances->resize(offsets.total_size());
984
985 /* Makes sure generic output attributes exists. */
986 for (const int attribute_index : all_instances_attributes.index_range()) {
988 const StringRef id = all_instances_attributes.ids[attribute_index];
989 const bke::AttrType type = all_instances_attributes.kinds[attribute_index].data_type;
990 dst_instances->attributes_for_write()
991 .lookup_or_add_for_write_only_span(id, domain, type)
992 .finish();
993 }
994
995 MutableSpan<float4x4> all_transforms = dst_instances->transforms_for_write();
996 MutableSpan<int> all_handles = dst_instances->reference_handles_for_write();
997
998 for (const int component_index : src_components.index_range()) {
999 const bke::InstancesComponent &src_component = static_cast<const bke::InstancesComponent &>(
1000 *src_components[component_index]);
1001 const bke::Instances &src_instances = *src_component.get();
1002 const blender::float4x4 &src_base_transform = src_base_transforms[component_index];
1003 const Span<const void *> attribute_fallback_array = attribute_fallback[component_index].array;
1004 const Span<bke::InstanceReference> src_references = src_instances.references();
1005 Array<int> handle_map(src_references.size());
1006
1007 for (const int src_handle : src_references.index_range()) {
1008 handle_map[src_handle] = dst_instances->add_reference(src_references[src_handle]);
1009 }
1010 const IndexRange dst_range = offsets[component_index];
1011 for (const int attribute_index : all_instances_attributes.index_range()) {
1012 const StringRef id = all_instances_attributes.ids[attribute_index];
1013 const bke::AttrType type = all_instances_attributes.kinds[attribute_index].data_type;
1014 const CPPType &cpp_type = bke::attribute_type_to_cpp_type(type);
1015 bke::GSpanAttributeWriter write_attribute =
1016 dst_instances->attributes_for_write().lookup_for_write_span(id);
1017 GMutableSpan dst_span = write_attribute.span;
1018
1019 const void *attribute_ptr;
1020 if (attribute_fallback_array[attribute_index] != nullptr) {
1021 attribute_ptr = attribute_fallback_array[attribute_index];
1022 }
1023 else {
1024 attribute_ptr = cpp_type.default_value();
1025 }
1026
1027 cpp_type.fill_assign_n(attribute_ptr, dst_span.slice(dst_range).data(), dst_range.size());
1028 write_attribute.finish();
1029 }
1030
1031 const Span<int> src_handles = src_instances.reference_handles();
1032 array_utils::gather(handle_map.as_span(), src_handles, all_handles.slice(dst_range));
1033 array_utils::copy(src_instances.transforms(), all_transforms.slice(dst_range));
1034
1035 for (blender::float4x4 &transform : all_transforms.slice(dst_range)) {
1036 transform = src_base_transform * transform;
1037 }
1038 }
1039
1040 r_realized_geometry.replace_instances(dst_instances.release());
1041 auto &dst_component = r_realized_geometry.get_component_for_write<bke::InstancesComponent>();
1042
1043 Vector<const bke::GeometryComponent *> for_join_attributes;
1044 for (bke::GeometryComponentPtr component : src_components) {
1045 for_join_attributes.append(component.get());
1046 }
1047 /* Join attribute values from the 'unselected' instances, as they aren't included otherwise.
1048 * Omit instance_transform and .reference_index to prevent them from overwriting the correct
1049 * attributes of the realized instances. */
1050 join_attributes(for_join_attributes, dst_component, {".reference_index", "instance_transform"});
1051}
1052
1054
1055/* -------------------------------------------------------------------- */
1058
1060 const bke::GeometrySet &in_geometry_set,
1062 const VariedDepthOptions &varied_depth_option,
1063 bool &r_create_radii,
1064 bool &r_create_id)
1065{
1067 in_geometry_set, bke::GeometryComponent::Type::PointCloud, options, varied_depth_option);
1068 OrderedAttributes ordered_attributes;
1069 for (const int i : attributes_to_propagate.names.index_range()) {
1070 if (attributes_to_propagate.names[i] == "position") {
1071 continue;
1072 }
1073 if (attributes_to_propagate.names[i] == "id") {
1074 r_create_id = true;
1075 continue;
1076 }
1077 if (attributes_to_propagate.names[i] == "radius") {
1078 r_create_radii = true;
1079 continue;
1080 }
1081 ordered_attributes.ids.add_new(attributes_to_propagate.names[i]);
1082 ordered_attributes.kinds.append(attributes_to_propagate.kinds[i]);
1083 }
1084 return ordered_attributes;
1085}
1086
1087static void gather_pointclouds_to_realize(const bke::GeometrySet &geometry_set,
1088 VectorSet<const PointCloud *> &r_pointclouds)
1089{
1090 if (const PointCloud *pointcloud = geometry_set.get_pointcloud()) {
1091 if (pointcloud->totpoint > 0) {
1092 r_pointclouds.add(pointcloud);
1093 }
1094 }
1095 if (const Instances *instances = geometry_set.get_instances()) {
1096 instances->foreach_referenced_geometry([&](const bke::GeometrySet &instance_geometry_set) {
1097 gather_pointclouds_to_realize(instance_geometry_set, r_pointclouds);
1098 });
1099 }
1100}
1101
1104 const VariedDepthOptions &varied_depth_option)
1105{
1106 AllPointCloudsInfo info;
1108 options,
1109 varied_depth_option,
1111 info.create_id_attribute);
1112
1113 gather_pointclouds_to_realize(geometry_set, info.order);
1114 info.realize_info.reinitialize(info.order.size());
1115 for (const int pointcloud_index : info.realize_info.index_range()) {
1116 PointCloudRealizeInfo &pointcloud_info = info.realize_info[pointcloud_index];
1117 const PointCloud *pointcloud = info.order[pointcloud_index];
1118 pointcloud_info.pointcloud = pointcloud;
1119
1120 /* Access attributes. */
1121 bke::AttributeAccessor attributes = pointcloud->attributes();
1122 pointcloud_info.attributes.reinitialize(info.attributes.size());
1123 for (const int attribute_index : info.attributes.index_range()) {
1124 const StringRef attribute_id = info.attributes.ids[attribute_index];
1125 const bke::AttrType data_type = info.attributes.kinds[attribute_index].data_type;
1126 const bke::AttrDomain domain = info.attributes.kinds[attribute_index].domain;
1127 if (attributes.contains(attribute_id)) {
1128 GVArray attribute = *attributes.lookup_or_default(attribute_id, domain, data_type);
1129 pointcloud_info.attributes[attribute_index].emplace(std::move(attribute));
1130 }
1131 }
1132 if (info.create_id_attribute) {
1133 bke::GAttributeReader ids_attribute = attributes.lookup("id");
1134 if (ids_attribute && ids_attribute.domain == bke::AttrDomain::Point &&
1135 ids_attribute.varray.type().is<int>() && ids_attribute.varray.is_span())
1136 {
1137 pointcloud_info.stored_ids = ids_attribute.varray.get_internal_span().typed<int>();
1138 }
1139 }
1140 if (info.create_radius_attribute) {
1141 pointcloud_info.radii = *attributes.lookup_or_default(
1142 "radius", bke::AttrDomain::Point, 0.01f);
1143 }
1144 const VArray<float3> position_attribute = *attributes.lookup_or_default<float3>(
1145 "position", bke::AttrDomain::Point, float3(0));
1146 pointcloud_info.positions = position_attribute.get_internal_span();
1147 }
1148 return info;
1149}
1150
1153 const RealizePointCloudTask &task,
1154 const OrderedAttributes &ordered_attributes,
1155 MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
1156 MutableSpan<float> all_dst_radii,
1157 MutableSpan<int> all_dst_ids,
1158 MutableSpan<float3> all_dst_positions)
1159{
1160 const PointCloudRealizeInfo &pointcloud_info = *task.pointcloud_info;
1161 const PointCloud &pointcloud = *pointcloud_info.pointcloud;
1162 const IndexRange point_slice{task.start_index, pointcloud.totpoint};
1163
1165 pointcloud_info.positions, task.transform, all_dst_positions.slice(point_slice));
1166
1167 /* Create point ids. */
1168 if (!all_dst_ids.is_empty()) {
1170 options, pointcloud_info.stored_ids, task.id, all_dst_ids.slice(point_slice));
1171 }
1172 if (!all_dst_radii.is_empty()) {
1173 pointcloud_info.radii.materialize(all_dst_radii.slice(point_slice));
1174 }
1175
1177 pointcloud_info.attributes,
1179 ordered_attributes,
1180 [&](const bke::AttrDomain domain) {
1181 BLI_assert(domain == bke::AttrDomain::Point);
1182 UNUSED_VARS_NDEBUG(domain);
1183 return point_slice;
1184 },
1185 dst_attribute_writers);
1186}
1187
1189 const OrderedAttributes &ordered_attributes,
1190 const AttributeFallbacksArray &attribute_fallbacks,
1192{
1193 for (const int attribute_index : ordered_attributes.index_range()) {
1194 const void *value = attribute_fallbacks.array[attribute_index];
1195 if (!value) {
1196 continue;
1197 }
1198 const bke::AttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
1199 const bke::AttrType data_type = ordered_attributes.kinds[attribute_index].data_type;
1200 const CPPType &cpp_type = bke::attribute_type_to_cpp_type(data_type);
1201 GVArray gvaray(GVArray::from_single(cpp_type, attributes.domain_size(domain), value));
1202 attributes.add(ordered_attributes.ids[attribute_index],
1203 domain,
1204 data_type,
1205 bke::AttributeInitVArray(std::move(gvaray)));
1206 }
1207}
1209 const GatherOffsets &offsets,
1210 const AllPointCloudsInfo &all_pointclouds_info,
1211 const Span<RealizePointCloudTask> tasks,
1212 const OrderedAttributes &ordered_attributes,
1213 RealizeInstancesResult &r_result)
1214{
1215 if (tasks.is_empty()) {
1216 return;
1217 }
1218
1219 if (tasks.size() == 1) {
1220 const RealizePointCloudTask &task = tasks.first();
1222 if (!skip_transform(task.transform)) {
1223 math::transform_points(task.transform, new_points->positions_for_write());
1224 new_points->tag_positions_changed();
1225 }
1227 ordered_attributes, task.attribute_fallbacks, new_points->attributes_for_write());
1228 r_result.geometry.replace_pointcloud(new_points);
1229 return;
1230 }
1231
1232 const int64_t tot_points = offsets.pointcloud_offset;
1233 if (!valid_int_num(tot_points)) {
1234 r_result.errors.append(RPT_("Realized point cloud has too many points."));
1235 return;
1236 }
1237
1238 /* Allocate new point cloud. */
1239 PointCloud *dst_pointcloud = BKE_pointcloud_new_nomain(tot_points);
1240 r_result.geometry.replace_pointcloud(dst_pointcloud);
1241 bke::MutableAttributeAccessor dst_attributes = dst_pointcloud->attributes_for_write();
1242
1243 const RealizePointCloudTask &first_task = tasks.first();
1244 const PointCloud &first_pointcloud = *first_task.pointcloud_info->pointcloud;
1245 dst_pointcloud->mat = static_cast<Material **>(MEM_dupallocN(first_pointcloud.mat));
1246 dst_pointcloud->totcol = first_pointcloud.totcol;
1247
1249 "position", bke::AttrDomain::Point);
1250
1251 /* Prepare id attribute. */
1252 SpanAttributeWriter<int> point_ids;
1253 if (all_pointclouds_info.create_id_attribute) {
1254 point_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id",
1256 }
1257 SpanAttributeWriter<float> point_radii;
1258 if (all_pointclouds_info.create_radius_attribute) {
1259 point_radii = dst_attributes.lookup_or_add_for_write_only_span<float>("radius",
1261 }
1262
1263 /* Prepare generic output attributes. */
1264 Vector<GSpanAttributeWriter> dst_attribute_writers;
1265 for (const int attribute_index : ordered_attributes.index_range()) {
1266 const StringRef attribute_id = ordered_attributes.ids[attribute_index];
1267 const bke::AttrType data_type = ordered_attributes.kinds[attribute_index].data_type;
1268 dst_attribute_writers.append(dst_attributes.lookup_or_add_for_write_only_span(
1269 attribute_id, bke::AttrDomain::Point, data_type));
1270 }
1271
1272 /* Actually execute all tasks. */
1273 threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
1274 for (const int task_index : task_range) {
1275 const RealizePointCloudTask &task = tasks[task_index];
1276 execute_realize_pointcloud_task(options,
1277 task,
1278 ordered_attributes,
1279 dst_attribute_writers,
1280 point_radii.span,
1281 point_ids.span,
1282 positions.span);
1283 }
1284 });
1285
1286 /* Tag modified attributes. */
1287 for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
1288 dst_attribute.finish();
1289 }
1290 positions.finish();
1291 point_radii.finish();
1292 point_ids.finish();
1293}
1294
1296
1297/* -------------------------------------------------------------------- */
1300
1302 const bke::GeometrySet &in_geometry_set,
1304 const VariedDepthOptions &varied_depth_option,
1305 bool &r_create_id,
1306 bool &r_create_material_index)
1307{
1309 in_geometry_set, bke::GeometryComponent::Type::Mesh, options, varied_depth_option);
1310 OrderedAttributes ordered_attributes;
1311 for (const int i : attributes_to_propagate.names.index_range()) {
1312 if (ELEM(attributes_to_propagate.names[i],
1313 "position",
1314 ".edge_verts",
1315 ".corner_vert",
1316 ".corner_edge",
1317 "custom_normal"))
1318 {
1319 continue;
1320 }
1321 if (attributes_to_propagate.names[i] == "id") {
1322 r_create_id = true;
1323 continue;
1324 }
1325 if (attributes_to_propagate.names[i] == "material_index") {
1326 r_create_material_index = true;
1327 continue;
1328 }
1329 ordered_attributes.ids.add_new(attributes_to_propagate.names[i]);
1330 ordered_attributes.kinds.append(attributes_to_propagate.kinds[i]);
1331 }
1332 return ordered_attributes;
1333}
1334
1335static void gather_meshes_to_realize(const bke::GeometrySet &geometry_set,
1336 VectorSet<const Mesh *> &r_meshes)
1337{
1338 if (const Mesh *mesh = geometry_set.get_mesh()) {
1339 if (mesh->verts_num > 0) {
1340 r_meshes.add(mesh);
1341 }
1342 }
1343 if (const Instances *instances = geometry_set.get_instances()) {
1344 instances->foreach_referenced_geometry([&](const bke::GeometrySet &instance_geometry_set) {
1345 gather_meshes_to_realize(instance_geometry_set, r_meshes);
1346 });
1347 }
1348}
1349
1352 const VariedDepthOptions &varied_depth_option)
1353{
1354 AllMeshesInfo info;
1356 geometry_set,
1357 options,
1358 varied_depth_option,
1361
1362 gather_meshes_to_realize(geometry_set, info.order);
1363 for (const Mesh *mesh : info.order) {
1364 if (mesh->totcol == 0) {
1365 /* Add an empty material slot for the default material. */
1366 info.materials.add(nullptr);
1367 }
1368 else {
1369 for (const int slot_index : IndexRange(mesh->totcol)) {
1370 Material *material = mesh->mat[slot_index];
1371 info.materials.add(material);
1372 }
1373 }
1374 }
1375
1376 for (const Mesh *mesh : info.order) {
1377 info.custom_normal_info.add_mesh(*mesh);
1378 }
1379
1381 info.realize_info.reinitialize(info.order.size());
1382 for (const int mesh_index : info.realize_info.index_range()) {
1383 MeshRealizeInfo &mesh_info = info.realize_info[mesh_index];
1384 const Mesh *mesh = info.order[mesh_index];
1385 mesh_info.mesh = mesh;
1386 mesh_info.positions = mesh->vert_positions();
1387 mesh_info.edges = mesh->edges();
1388 mesh_info.faces = mesh->faces();
1389 mesh_info.corner_verts = mesh->corner_verts();
1390 mesh_info.corner_edges = mesh->corner_edges();
1391
1392 /* Create material index mapping. */
1393 mesh_info.material_index_map.reinitialize(std::max<int>(mesh->totcol, 1));
1394 if (mesh->totcol == 0) {
1395 mesh_info.material_index_map.first() = info.materials.index_of(nullptr);
1396 }
1397 else {
1398 for (const int old_slot_index : IndexRange(mesh->totcol)) {
1399 Material *material = mesh->mat[old_slot_index];
1400 const int new_slot_index = info.materials.index_of(material);
1401 mesh_info.material_index_map[old_slot_index] = new_slot_index;
1402 }
1403 }
1404
1405 /* Access attributes. */
1406 bke::AttributeAccessor attributes = mesh->attributes();
1407 mesh_info.attributes.reinitialize(info.attributes.size());
1408 for (const int attribute_index : info.attributes.index_range()) {
1409 const StringRef attribute_id = info.attributes.ids[attribute_index];
1410 const bke::AttrType data_type = info.attributes.kinds[attribute_index].data_type;
1411 const bke::AttrDomain domain = info.attributes.kinds[attribute_index].domain;
1412 if (attributes.contains(attribute_id)) {
1413 GVArray attribute = *attributes.lookup_or_default(attribute_id, domain, data_type);
1414 mesh_info.attributes[attribute_index].emplace(std::move(attribute));
1415 }
1416 }
1417 if (info.create_id_attribute) {
1418 bke::GAttributeReader ids_attribute = attributes.lookup("id");
1419 if (ids_attribute && ids_attribute.domain == bke::AttrDomain::Point &&
1420 ids_attribute.varray.type().is<int>() && ids_attribute.varray.is_span())
1421 {
1422 mesh_info.stored_vertex_ids = ids_attribute.varray.get_internal_span().typed<int>();
1423 }
1424 }
1425 mesh_info.material_indices = *attributes.lookup_or_default<int>(
1426 "material_index", bke::AttrDomain::Face, 0);
1427
1428 switch (info.custom_normal_info.result_type) {
1430 break;
1431 }
1433 if (const bke::GAttributeReader custom_normal = attributes.lookup("custom_normal")) {
1434 const bke::AttributeMetaData meta_data{
1435 custom_normal.domain, bke::cpp_type_to_attribute_type(custom_normal.varray.type())};
1436 if (bke::mesh::is_corner_fan_normals(meta_data)) {
1437 mesh_info.custom_normal = custom_normal.varray.typed<short2>();
1438 }
1439 }
1440 break;
1441 }
1443 switch (*info.custom_normal_info.result_domain) {
1445 mesh_info.custom_normal = VArray<float3>::from_span(mesh->vert_normals());
1446 break;
1448 mesh_info.custom_normal = VArray<float3>::from_span(mesh->face_normals());
1449 break;
1451 mesh_info.custom_normal = VArray<float3>::from_span(mesh->corner_normals());
1452 break;
1453 default:
1455 }
1456 break;
1457 }
1458 }
1459 }
1460
1461 info.no_loose_edges_hint = std::all_of(
1462 info.order.begin(), info.order.end(), [](const Mesh *mesh) {
1463 return mesh->runtime->loose_edges_cache.is_cached() && mesh->loose_edges().count == 0;
1464 });
1465 info.no_loose_verts_hint = std::all_of(
1466 info.order.begin(), info.order.end(), [](const Mesh *mesh) {
1467 return mesh->runtime->loose_verts_cache.is_cached() && mesh->loose_verts().count == 0;
1468 });
1469 info.no_overlapping_hint = std::all_of(
1470 info.order.begin(), info.order.end(), [](const Mesh *mesh) {
1471 return mesh->no_overlapping_topology();
1472 });
1473
1474 return info;
1475}
1476
1478 const RealizeMeshTask &task,
1479 const OrderedAttributes &ordered_attributes,
1480 MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
1481 MutableSpan<float3> all_dst_positions,
1482 MutableSpan<int2> all_dst_edges,
1483 MutableSpan<int> all_dst_face_offsets,
1484 MutableSpan<int> all_dst_corner_verts,
1485 MutableSpan<int> all_dst_corner_edges,
1486 MutableSpan<int> all_dst_vertex_ids,
1487 MutableSpan<int> all_dst_material_indices,
1488 GSpanAttributeWriter &all_dst_custom_normals)
1489{
1490 const MeshRealizeInfo &mesh_info = *task.mesh_info;
1491 const Mesh &mesh = *mesh_info.mesh;
1492
1493 const Span<float3> src_positions = mesh_info.positions;
1494 const Span<int2> src_edges = mesh_info.edges;
1495 const OffsetIndices src_faces = mesh_info.faces;
1496 const Span<int> src_corner_verts = mesh_info.corner_verts;
1497 const Span<int> src_corner_edges = mesh_info.corner_edges;
1498
1499 const IndexRange dst_vert_range(task.start_indices.vertex, src_positions.size());
1500 const IndexRange dst_edge_range(task.start_indices.edge, src_edges.size());
1501 const IndexRange dst_face_range(task.start_indices.face, src_faces.size());
1502 const IndexRange dst_loop_range(task.start_indices.loop, src_corner_verts.size());
1503
1504 MutableSpan<float3> dst_positions = all_dst_positions.slice(dst_vert_range);
1505 MutableSpan<int2> dst_edges = all_dst_edges.slice(dst_edge_range);
1506 MutableSpan<int> dst_face_offsets = all_dst_face_offsets.slice(dst_face_range);
1507 MutableSpan<int> dst_corner_verts = all_dst_corner_verts.slice(dst_loop_range);
1508 MutableSpan<int> dst_corner_edges = all_dst_corner_edges.slice(dst_loop_range);
1509
1510 math::transform_points(src_positions, task.transform, dst_positions);
1511
1512 threading::parallel_for(src_edges.index_range(), 1024, [&](const IndexRange edge_range) {
1513 for (const int i : edge_range) {
1514 dst_edges[i] = src_edges[i] + task.start_indices.vertex;
1515 }
1516 });
1517 threading::parallel_for(src_corner_verts.index_range(), 1024, [&](const IndexRange loop_range) {
1518 for (const int i : loop_range) {
1519 dst_corner_verts[i] = src_corner_verts[i] + task.start_indices.vertex;
1520 }
1521 });
1522 threading::parallel_for(src_corner_edges.index_range(), 1024, [&](const IndexRange loop_range) {
1523 for (const int i : loop_range) {
1524 dst_corner_edges[i] = src_corner_edges[i] + task.start_indices.edge;
1525 }
1526 });
1527 threading::parallel_for(src_faces.index_range(), 1024, [&](const IndexRange face_range) {
1528 for (const int i : face_range) {
1529 dst_face_offsets[i] = src_faces[i].start() + task.start_indices.loop;
1530 }
1531 });
1532 if (!all_dst_material_indices.is_empty()) {
1533 const Span<int> material_index_map = mesh_info.material_index_map;
1534 MutableSpan<int> dst_material_indices = all_dst_material_indices.slice(dst_face_range);
1535 if (mesh.totcol == 0) {
1536 /* The material index map contains the index of the null material in the result. */
1537 dst_material_indices.fill(material_index_map.first());
1538 }
1539 else {
1540 if (mesh_info.material_indices.is_single()) {
1541 const int src_index = mesh_info.material_indices.get_internal_single();
1542 const bool valid = IndexRange(mesh.totcol).contains(src_index);
1543 dst_material_indices.fill(valid ? material_index_map[src_index] : 0);
1544 }
1545 else {
1546 VArraySpan<int> indices_span(mesh_info.material_indices);
1547 threading::parallel_for(src_faces.index_range(), 1024, [&](const IndexRange face_range) {
1548 for (const int i : face_range) {
1549 const int src_index = indices_span[i];
1550 const bool valid = IndexRange(mesh.totcol).contains(src_index);
1551 dst_material_indices[i] = valid ? material_index_map[src_index] : 0;
1552 }
1553 });
1554 }
1555 }
1556 }
1557
1558 if (!all_dst_vertex_ids.is_empty()) {
1560 mesh_info.stored_vertex_ids,
1561 task.id,
1562 all_dst_vertex_ids.slice(task.start_indices.vertex, mesh.verts_num));
1563 }
1564
1565 const auto domain_to_range = [&](const bke::AttrDomain domain) {
1566 switch (domain) {
1567 case bke::AttrDomain::Point:
1568 return dst_vert_range;
1569 case bke::AttrDomain::Edge:
1570 return dst_edge_range;
1571 case bke::AttrDomain::Face:
1572 return dst_face_range;
1573 case bke::AttrDomain::Corner:
1574 return dst_loop_range;
1575 default:
1577 return IndexRange();
1578 }
1579 };
1580
1581 if (all_dst_custom_normals) {
1582 if (all_dst_custom_normals.span.type().is<short2>()) {
1583 if (mesh_info.custom_normal.is_empty()) {
1584 all_dst_custom_normals.span.typed<short2>().slice(dst_loop_range).fill(short2(0));
1585 }
1586 else {
1587 all_dst_custom_normals.span.typed<short2>()
1588 .slice(dst_loop_range)
1589 .copy_from(mesh_info.custom_normal.typed<short2>());
1590 }
1591 }
1592 else {
1593 const IndexRange dst_range = domain_to_range(all_dst_custom_normals.domain);
1594 math::transform_normals(mesh_info.custom_normal.typed<float3>(),
1595 float3x3(task.transform),
1596 all_dst_custom_normals.span.typed<float3>().slice(dst_range));
1597 }
1598 }
1599
1600 copy_generic_attributes_to_result(mesh_info.attributes,
1601 task.attribute_fallbacks,
1602 ordered_attributes,
1603 domain_to_range,
1604 dst_attribute_writers);
1605}
1606static void copy_vertex_group_name(ListBase *dst_deform_group,
1607 const OrderedAttributes &ordered_attributes,
1608 const bDeformGroup &src_deform_group)
1609{
1610 const StringRef src_name = src_deform_group.name;
1611 const int attribute_index = ordered_attributes.ids.index_of_try(src_name);
1612 if (attribute_index == -1) {
1613 /* The attribute is not propagated to the result (possibly because the mesh isn't included
1614 * in the realized output because of the #VariedDepthOptions input). */
1615 return;
1616 }
1617 const bke::AttributeDomainAndType kind = ordered_attributes.kinds[attribute_index];
1619 /* Skip if the source attribute can't possibly contain vertex weights. */
1620 return;
1621 }
1622 bDeformGroup *dst = MEM_callocN<bDeformGroup>(__func__);
1623 src_name.copy_utf8_truncated(dst->name);
1624 BLI_addtail(dst_deform_group, dst);
1625}
1626
1627static void copy_vertex_group_names(Mesh &dst_mesh,
1628 const OrderedAttributes &ordered_attributes,
1629 const Span<const Mesh *> src_meshes)
1630{
1631 Set<StringRef> existing_names;
1632 LISTBASE_FOREACH (const bDeformGroup *, defgroup, &dst_mesh.vertex_group_names) {
1633 existing_names.add(defgroup->name);
1634 }
1635 for (const Mesh *mesh : src_meshes) {
1636 LISTBASE_FOREACH (const bDeformGroup *, src, &mesh->vertex_group_names) {
1637 if (existing_names.contains(src->name)) {
1638 continue;
1639 }
1640 copy_vertex_group_name(&dst_mesh.vertex_group_names, ordered_attributes, *src);
1641 }
1642 }
1643}
1644
1646 const GatherOffsets &offsets,
1647 const AllMeshesInfo &all_meshes_info,
1648 const Span<RealizeMeshTask> tasks,
1649 const OrderedAttributes &ordered_attributes,
1650 const VectorSet<Material *> &ordered_materials,
1651 RealizeInstancesResult &r_result)
1652{
1653 if (tasks.is_empty()) {
1654 return;
1655 }
1656
1657 if (tasks.size() == 1) {
1658 const RealizeMeshTask &task = tasks.first();
1659 Mesh *new_mesh = BKE_mesh_copy_for_eval(*task.mesh_info->mesh);
1660 if (!skip_transform(task.transform)) {
1661 bke::mesh_transform(*new_mesh, task.transform, false);
1662 }
1664 ordered_attributes, task.attribute_fallbacks, new_mesh->attributes_for_write());
1665 r_result.geometry.replace_mesh(new_mesh);
1666 return;
1667 }
1668
1669 const int64_t tot_vertices = offsets.mesh_offsets.vertex;
1670 const int64_t tot_edges = offsets.mesh_offsets.edge;
1671 const int64_t tot_loops = offsets.mesh_offsets.corner;
1672 const int64_t tot_faces = offsets.mesh_offsets.face;
1673
1674 if (!valid_int_num(tot_vertices) || !valid_int_num(tot_edges) || !valid_int_num(tot_loops) ||
1675 !valid_int_num(tot_faces))
1676 {
1677 r_result.errors.append(RPT_("Realized mesh has too many elements."));
1678 return;
1679 }
1680
1681 Mesh *dst_mesh = BKE_mesh_new_nomain(tot_vertices, tot_edges, tot_faces, tot_loops);
1682 r_result.geometry.replace_mesh(dst_mesh);
1683 bke::MutableAttributeAccessor dst_attributes = dst_mesh->attributes_for_write();
1684 MutableSpan<float3> dst_positions = dst_mesh->vert_positions_for_write();
1685 MutableSpan<int2> dst_edges = dst_mesh->edges_for_write();
1686 MutableSpan<int> dst_face_offsets = dst_mesh->face_offsets_for_write();
1687 MutableSpan<int> dst_corner_verts = dst_mesh->corner_verts_for_write();
1688 MutableSpan<int> dst_corner_edges = dst_mesh->corner_edges_for_write();
1689
1690 /* Copy settings from the first input geometry set with a mesh. */
1691 const RealizeMeshTask &first_task = tasks.first();
1692 const Mesh &first_mesh = *first_task.mesh_info->mesh;
1693 BKE_mesh_copy_parameters_for_eval(dst_mesh, &first_mesh);
1694
1698 *dst_mesh, ordered_attributes, all_meshes_info.order.as_span().drop_front(1));
1700
1701 /* Add materials. */
1702 for (const int i : IndexRange(ordered_materials.size())) {
1703 Material *material = ordered_materials[i];
1704 BKE_id_material_eval_assign(&dst_mesh->id, i + 1, material);
1705 }
1706
1707 /* Prepare id attribute. */
1708 SpanAttributeWriter<int> vertex_ids;
1709 if (all_meshes_info.create_id_attribute) {
1710 vertex_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id",
1712 }
1713 /* Prepare material indices. */
1714 SpanAttributeWriter<int> material_indices;
1715 if (all_meshes_info.create_material_index_attribute) {
1716 material_indices = dst_attributes.lookup_or_add_for_write_only_span<int>(
1717 "material_index", bke::AttrDomain::Face);
1718 }
1719
1720 GSpanAttributeWriter custom_normals;
1721 switch (all_meshes_info.custom_normal_info.result_type) {
1723 break;
1724 }
1726 custom_normals = dst_attributes.lookup_or_add_for_write_only_span(
1728 break;
1729 }
1731 const bke::AttrDomain domain = *all_meshes_info.custom_normal_info.result_domain;
1732 custom_normals = dst_attributes.lookup_or_add_for_write_only_span(
1733 "custom_normal", domain, bke::AttrType::Float3);
1734 break;
1735 }
1736 }
1737
1738 /* Prepare generic output attributes. */
1739 Vector<GSpanAttributeWriter> dst_attribute_writers;
1740 for (const int attribute_index : ordered_attributes.index_range()) {
1741 const StringRef attribute_id = ordered_attributes.ids[attribute_index];
1742 const bke::AttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
1743 const bke::AttrType data_type = ordered_attributes.kinds[attribute_index].data_type;
1744 dst_attribute_writers.append(
1745 dst_attributes.lookup_or_add_for_write_only_span(attribute_id, domain, data_type));
1746 }
1747 const char *active_layer = CustomData_get_active_layer_name(&first_mesh.corner_data,
1749 if (active_layer != nullptr) {
1750 int id = CustomData_get_named_layer(&dst_mesh->corner_data, CD_PROP_FLOAT2, active_layer);
1751 if (id >= 0) {
1753 }
1754 }
1755 const char *render_layer = CustomData_get_render_layer_name(&first_mesh.corner_data,
1757 if (render_layer != nullptr) {
1758 int id = CustomData_get_named_layer(&dst_mesh->corner_data, CD_PROP_FLOAT2, render_layer);
1759 if (id >= 0) {
1761 }
1762 }
1763 /* Actually execute all tasks. */
1764 threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
1765 for (const int task_index : task_range) {
1766 const RealizeMeshTask &task = tasks[task_index];
1767 execute_realize_mesh_task(options,
1768 task,
1769 ordered_attributes,
1770 dst_attribute_writers,
1771 dst_positions,
1772 dst_edges,
1773 dst_face_offsets,
1774 dst_corner_verts,
1775 dst_corner_edges,
1776 vertex_ids.span,
1777 material_indices.span,
1778 custom_normals);
1779 }
1780 });
1781
1782 /* Tag modified attributes. */
1783 for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
1784 dst_attribute.finish();
1785 }
1786 vertex_ids.finish();
1787 material_indices.finish();
1788 custom_normals.finish();
1789
1790 if (all_meshes_info.no_loose_edges_hint) {
1791 dst_mesh->tag_loose_edges_none();
1792 }
1793 if (all_meshes_info.no_loose_verts_hint) {
1794 dst_mesh->tag_loose_verts_none();
1795 }
1796 if (all_meshes_info.no_overlapping_hint) {
1797 dst_mesh->tag_overlapping_none();
1798 }
1799}
1800
1802
1803/* -------------------------------------------------------------------- */
1806
1808 const bke::GeometrySet &in_geometry_set,
1810 const VariedDepthOptions &varied_depth_option,
1811 bool &r_create_id)
1812{
1814 in_geometry_set, bke::GeometryComponent::Type::Curve, options, varied_depth_option);
1815 OrderedAttributes ordered_attributes;
1816 for (const int i : attributes_to_propagate.names.index_range()) {
1817 if (ELEM(attributes_to_propagate.names[i],
1818 "position",
1819 "radius",
1820 "handle_left",
1821 "handle_right",
1822 "custom_normal"))
1823 {
1824 continue;
1825 }
1826 if (attributes_to_propagate.names[i] == "id") {
1827 r_create_id = true;
1828 continue;
1829 }
1830 ordered_attributes.ids.add_new(attributes_to_propagate.names[i]);
1831 ordered_attributes.kinds.append(attributes_to_propagate.kinds[i]);
1832 }
1833 return ordered_attributes;
1834}
1835
1836static void gather_curves_to_realize(const bke::GeometrySet &geometry_set,
1837 VectorSet<const Curves *> &r_curves)
1838{
1839 if (const Curves *curves = geometry_set.get_curves()) {
1840 if (curves->geometry.curve_num != 0) {
1841 r_curves.add(curves);
1842 }
1843 }
1844 if (const Instances *instances = geometry_set.get_instances()) {
1845 instances->foreach_referenced_geometry([&](const bke::GeometrySet &instance_geometry_set) {
1846 gather_curves_to_realize(instance_geometry_set, r_curves);
1847 });
1848 }
1849}
1850
1853 const VariedDepthOptions &varied_depth_option)
1854{
1855 AllCurvesInfo info;
1857 geometry_set, options, varied_depth_option, info.create_id_attribute);
1858
1859 gather_curves_to_realize(geometry_set, info.order);
1860 info.realize_info.reinitialize(info.order.size());
1861 for (const int curve_index : info.realize_info.index_range()) {
1862 RealizeCurveInfo &curve_info = info.realize_info[curve_index];
1863 const Curves *curves_id = info.order[curve_index];
1864 const bke::CurvesGeometry &curves = curves_id->geometry.wrap();
1865 curve_info.curves = curves_id;
1866
1867 /* Access attributes. */
1868 bke::AttributeAccessor attributes = curves.attributes();
1869 curve_info.attributes.reinitialize(info.attributes.size());
1870 for (const int attribute_index : info.attributes.index_range()) {
1871 const bke::AttrDomain domain = info.attributes.kinds[attribute_index].domain;
1872 const StringRef attribute_id = info.attributes.ids[attribute_index];
1873 const bke::AttrType data_type = info.attributes.kinds[attribute_index].data_type;
1874 if (attributes.contains(attribute_id)) {
1875 GVArray attribute = *attributes.lookup_or_default(attribute_id, domain, data_type);
1876 curve_info.attributes[attribute_index].emplace(std::move(attribute));
1877 }
1878 }
1879 if (info.create_id_attribute) {
1880 bke::GAttributeReader id_attribute = attributes.lookup("id");
1881 if (id_attribute && id_attribute.domain == bke::AttrDomain::Point &&
1882 id_attribute.varray.type().is<int>() && id_attribute.varray.is_span())
1883 {
1884 curve_info.stored_ids = id_attribute.varray.get_internal_span().typed<int>();
1885 }
1886 }
1887
1888 if (attributes.contains("radius")) {
1889 curve_info.radius =
1890 attributes.lookup<float>("radius", bke::AttrDomain::Point).varray.get_internal_span();
1891 info.create_radius_attribute = true;
1892 }
1893 if (attributes.contains("handle_right")) {
1894 curve_info.handle_left = attributes.lookup<float3>("handle_left", bke::AttrDomain::Point)
1895 .varray.get_internal_span();
1896 curve_info.handle_right = attributes.lookup<float3>("handle_right", bke::AttrDomain::Point)
1897 .varray.get_internal_span();
1899 }
1900 if (attributes.contains("custom_normal")) {
1901 curve_info.custom_normal = attributes.lookup<float3>("custom_normal", bke::AttrDomain::Point)
1902 .varray.get_internal_span();
1904 }
1905 }
1906 return info;
1907}
1908
1910 InstanceContext &attribute_fallbacks)
1911{
1912 if (all_curves_info.order.is_empty()) {
1913 return;
1914 }
1915 const Curves *first = all_curves_info.order[0];
1916 const bke::CurvesGeometry &first_curves = first->geometry.wrap();
1917 for (const int attribute_i : attribute_fallbacks.curves.array.index_range()) {
1918 const StringRef attribute_id = all_curves_info.attributes.ids[attribute_i];
1919 if (first_curves.attributes().is_builtin(attribute_id)) {
1920 attribute_fallbacks.curves.array[attribute_i] =
1921 first_curves.attributes().get_builtin_default(attribute_id).get();
1922 }
1923 }
1924}
1925
1927 const AllCurvesInfo &all_curves_info,
1928 const RealizeCurveTask &task,
1929 const OrderedAttributes &ordered_attributes,
1930 bke::CurvesGeometry &dst_curves,
1931 MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
1932 MutableSpan<int> all_dst_ids,
1933 MutableSpan<float3> all_handle_left,
1934 MutableSpan<float3> all_handle_right,
1935 MutableSpan<float> all_radii,
1936 MutableSpan<float3> all_custom_normals)
1937{
1938 const RealizeCurveInfo &curves_info = *task.curve_info;
1939 const Curves &curves_id = *curves_info.curves;
1940 const bke::CurvesGeometry &curves = curves_id.geometry.wrap();
1941
1942 const IndexRange dst_point_range{task.start_indices.point, curves.points_num()};
1943 const IndexRange dst_curve_range{task.start_indices.curve, curves.curves_num()};
1944 const IndexRange dst_custom_knot_range{task.start_indices.custom_knot,
1945 curves.nurbs_custom_knots_by_curve().total_size()};
1946
1948 curves.positions(), task.transform, dst_curves.positions_for_write().slice(dst_point_range));
1949
1950 /* Copy and transform handle positions if necessary. */
1951 if (all_curves_info.create_handle_postion_attributes) {
1952 if (curves_info.handle_left.is_empty()) {
1953 all_handle_left.slice(dst_point_range).fill(float3(0));
1954 }
1955 else {
1957 curves_info.handle_left, task.transform, all_handle_left.slice(dst_point_range));
1958 }
1959 if (curves_info.handle_right.is_empty()) {
1960 all_handle_right.slice(dst_point_range).fill(float3(0));
1961 }
1962 else {
1964 curves_info.handle_right, task.transform, all_handle_right.slice(dst_point_range));
1965 }
1966 }
1967
1968 if (all_curves_info.create_radius_attribute) {
1969 if (curves_info.radius.is_empty()) {
1970 all_radii.slice(dst_point_range).fill(1.0f);
1971 }
1972 else {
1973 all_radii.slice(dst_point_range).copy_from(curves_info.radius);
1974 }
1975 }
1976
1977 if (all_curves_info.create_custom_normal_attribute) {
1978 if (curves_info.custom_normal.is_empty()) {
1979 all_custom_normals.slice(dst_point_range).fill(float3(0, 0, 1));
1980 }
1981 else {
1983 float3x3(task.transform),
1984 all_custom_normals.slice(dst_point_range));
1985 }
1986 }
1987
1988 /* Copy curve offsets. */
1989 const Span<int> src_offsets = curves.offsets();
1990 const MutableSpan<int> dst_offsets = dst_curves.offsets_for_write().slice(dst_curve_range);
1991 threading::parallel_for(curves.curves_range(), 2048, [&](const IndexRange range) {
1992 for (const int i : range) {
1993 dst_offsets[i] = task.start_indices.point + src_offsets[i];
1994 }
1995 });
1996
1997 dst_curves.nurbs_custom_knots_for_write()
1998 .slice(dst_custom_knot_range)
1999 .copy_from(curves.nurbs_custom_knots());
2000
2001 if (!all_dst_ids.is_empty()) {
2002 create_result_ids(
2003 options, curves_info.stored_ids, task.id, all_dst_ids.slice(dst_point_range));
2004 }
2005
2006 copy_generic_attributes_to_result(
2007 curves_info.attributes,
2008 task.attribute_fallbacks,
2009 ordered_attributes,
2010 [&](const bke::AttrDomain domain) {
2011 switch (domain) {
2012 case bke::AttrDomain::Point:
2013 return IndexRange(task.start_indices.point, curves.points_num());
2014 case bke::AttrDomain::Curve:
2015 return IndexRange(task.start_indices.curve, curves.curves_num());
2016 default:
2017 BLI_assert_unreachable();
2018 return IndexRange();
2019 }
2020 },
2021 dst_attribute_writers);
2022}
2023
2025 const OrderedAttributes &ordered_attributes,
2026 const Span<const Curves *> src_curves)
2027{
2028 Set<StringRef> existing_names;
2029 LISTBASE_FOREACH (const bDeformGroup *, defgroup, &dst_curve.vertex_group_names) {
2030 existing_names.add(defgroup->name);
2031 }
2032 for (const Curves *src_curve : src_curves) {
2033 LISTBASE_FOREACH (const bDeformGroup *, src, &src_curve->geometry.vertex_group_names) {
2034 if (existing_names.contains(src->name)) {
2035 continue;
2036 }
2037 copy_vertex_group_name(&dst_curve.vertex_group_names, ordered_attributes, *src);
2038 existing_names.add(src->name);
2039 }
2040 }
2041}
2042
2044 const GatherOffsets &offsets,
2045 const AllCurvesInfo &all_curves_info,
2046 const Span<RealizeCurveTask> tasks,
2047 const OrderedAttributes &ordered_attributes,
2048 RealizeInstancesResult &r_result)
2049{
2050 if (tasks.is_empty()) {
2051 return;
2052 }
2053
2054 if (tasks.size() == 1) {
2055 const RealizeCurveTask &task = tasks.first();
2056 Curves *new_curves = BKE_curves_copy_for_eval(task.curve_info->curves);
2057 if (!skip_transform(task.transform)) {
2058 new_curves->geometry.wrap().transform(task.transform);
2059 }
2062 new_curves->geometry.wrap().attributes_for_write());
2063 r_result.geometry.replace_curves(new_curves);
2064 return;
2065 }
2066
2067 const int64_t points_num = offsets.curves_offsets.point;
2068 const int64_t curves_num = offsets.curves_offsets.curve;
2069 const int64_t custom_knot_num = offsets.curves_offsets.custom_knot;
2070
2071 if (!valid_int_num(points_num) || !valid_int_num(curves_num) || !valid_int_num(custom_knot_num))
2072 {
2073 r_result.errors.append(RPT_("Realized curves data has too many elements."));
2074 return;
2075 }
2076
2077 /* Allocate new curves data-block. */
2078 Curves *dst_curves_id = bke::curves_new_nomain(points_num, curves_num);
2079 bke::CurvesGeometry &dst_curves = dst_curves_id->geometry.wrap();
2080 if (custom_knot_num) {
2081 dst_curves.nurbs_custom_knots_resize(custom_knot_num);
2082 }
2083 dst_curves.offsets_for_write().last() = points_num;
2084 r_result.geometry.replace_curves(dst_curves_id);
2085 bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
2086
2087 /* Copy settings from the first input geometry set with curves. */
2088 const RealizeCurveTask &first_task = tasks.first();
2089 const Curves &first_curves_id = *first_task.curve_info->curves;
2090 bke::curves_copy_parameters(first_curves_id, *dst_curves_id);
2091
2092 copy_vertex_group_names(dst_curves, ordered_attributes, all_curves_info.order);
2093
2094 /* Prepare id attribute. */
2095 SpanAttributeWriter<int> point_ids;
2096 if (all_curves_info.create_id_attribute) {
2097 point_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id",
2099 }
2100
2101 /* Prepare generic output attributes. */
2102 Vector<GSpanAttributeWriter> dst_attribute_writers;
2103 for (const int attribute_index : ordered_attributes.index_range()) {
2104 const StringRef attribute_id = ordered_attributes.ids[attribute_index];
2105 const bke::AttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
2106 const bke::AttrType data_type = ordered_attributes.kinds[attribute_index].data_type;
2107 dst_attribute_writers.append(
2108 dst_attributes.lookup_or_add_for_write_only_span(attribute_id, domain, data_type));
2109 }
2110
2111 /* Prepare handle position attributes if necessary. */
2112 SpanAttributeWriter<float3> handle_left;
2113 SpanAttributeWriter<float3> handle_right;
2114 if (all_curves_info.create_handle_postion_attributes) {
2115 handle_left = dst_attributes.lookup_or_add_for_write_only_span<float3>("handle_left",
2117 handle_right = dst_attributes.lookup_or_add_for_write_only_span<float3>(
2118 "handle_right", bke::AttrDomain::Point);
2119 }
2120
2122 if (all_curves_info.create_radius_attribute) {
2123 radius = dst_attributes.lookup_or_add_for_write_only_span<float>("radius",
2125 }
2126 SpanAttributeWriter<float3> custom_normal;
2127 if (all_curves_info.create_custom_normal_attribute) {
2128 custom_normal = dst_attributes.lookup_or_add_for_write_only_span<float3>(
2129 "custom_normal", bke::AttrDomain::Point);
2130 }
2131
2132 /* Actually execute all tasks. */
2133 threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
2134 for (const int task_index : task_range) {
2135 const RealizeCurveTask &task = tasks[task_index];
2136 execute_realize_curve_task(options,
2137 all_curves_info,
2138 task,
2139 ordered_attributes,
2140 dst_curves,
2141 dst_attribute_writers,
2142 point_ids.span,
2143 handle_left.span,
2144 handle_right.span,
2145 radius.span,
2146 custom_normal.span);
2147 }
2148 });
2149
2150 /* Type counts have to be updated eagerly. */
2151 dst_curves.runtime->type_counts.fill(0);
2152 for (const RealizeCurveTask &task : tasks) {
2153 for (const int i : IndexRange(CURVE_TYPES_NUM)) {
2154 dst_curves.runtime->type_counts[i] +=
2155 task.curve_info->curves->geometry.runtime->type_counts[i];
2156 }
2157 }
2158
2159 /* Tag modified attributes. */
2160 for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
2161 dst_attribute.finish();
2162 }
2163 point_ids.finish();
2164 radius.finish();
2165 handle_left.finish();
2166 handle_right.finish();
2167 custom_normal.finish();
2168}
2169
2171
2172/* -------------------------------------------------------------------- */
2175
2177 const bke::GeometrySet &in_geometry_set,
2179 const VariedDepthOptions &varied_depth_options)
2180{
2182 in_geometry_set, bke::GeometryComponent::Type::GreasePencil, options, varied_depth_options);
2183 OrderedAttributes ordered_attributes;
2184 for (const int i : attributes_to_propagate.names.index_range()) {
2185 ordered_attributes.ids.add_new(attributes_to_propagate.names[i]);
2186 ordered_attributes.kinds.append(attributes_to_propagate.kinds[i]);
2187 }
2188 return ordered_attributes;
2189}
2190
2192 VectorSet<const GreasePencil *> &r_grease_pencils)
2193{
2194 if (const GreasePencil *grease_pencil = geometry_set.get_grease_pencil()) {
2195 if (!grease_pencil->layers().is_empty()) {
2196 r_grease_pencils.add(grease_pencil);
2197 }
2198 }
2199 if (const Instances *instances = geometry_set.get_instances()) {
2200 instances->foreach_referenced_geometry([&](const bke::GeometrySet &instance_geometry_set) {
2201 gather_grease_pencils_to_realize(instance_geometry_set, r_grease_pencils);
2202 });
2203 }
2204}
2205
2207 const bke::GeometrySet &geometry_set,
2209 const VariedDepthOptions &varied_depth_options)
2210{
2213 geometry_set, options, varied_depth_options);
2214
2215 gather_grease_pencils_to_realize(geometry_set, info.order);
2216 info.realize_info.reinitialize(info.order.size());
2217 for (const int grease_pencil_index : info.realize_info.index_range()) {
2218 GreasePencilRealizeInfo &grease_pencil_info = info.realize_info[grease_pencil_index];
2219 const GreasePencil *grease_pencil = info.order[grease_pencil_index];
2220 grease_pencil_info.grease_pencil = grease_pencil;
2221
2222 bke::AttributeAccessor attributes = grease_pencil->attributes();
2223 grease_pencil_info.attributes.reinitialize(info.attributes.size());
2224 for (const int attribute_index : info.attributes.index_range()) {
2225 const StringRef attribute_id = info.attributes.ids[attribute_index];
2226 const bke::AttrType data_type = info.attributes.kinds[attribute_index].data_type;
2227 const bke::AttrDomain domain = info.attributes.kinds[attribute_index].domain;
2228 if (attributes.contains(attribute_id)) {
2229 GVArray attribute = *attributes.lookup_or_default(attribute_id, domain, data_type);
2230 grease_pencil_info.attributes[attribute_index].emplace(std::move(attribute));
2231 }
2232 }
2233
2234 grease_pencil_info.material_index_map.reinitialize(grease_pencil->material_array_num);
2235 for (const int i : IndexRange(grease_pencil->material_array_num)) {
2236 Material *material = grease_pencil->material_array[i];
2237 grease_pencil_info.material_index_map[i] = info.materials.index_of_or_add(material);
2238 }
2239 }
2240 return info;
2241}
2242
2244 const RealizeGreasePencilTask &task,
2245 const OrderedAttributes &ordered_attributes,
2246 GreasePencil &dst_grease_pencil,
2247 MutableSpan<GSpanAttributeWriter> dst_attribute_writers)
2248{
2249 const GreasePencilRealizeInfo &grease_pencil_info = *task.grease_pencil_info;
2250 const GreasePencil &src_grease_pencil = *grease_pencil_info.grease_pencil;
2251 const Span<const bke::greasepencil::Layer *> src_layers = src_grease_pencil.layers();
2252 const IndexRange dst_layers_slice{task.start_index, src_layers.size()};
2253 const Span<bke::greasepencil::Layer *> dst_layers = dst_grease_pencil.layers_for_write().slice(
2254 dst_layers_slice);
2255
2256 for (const int layer_i : src_layers.index_range()) {
2257 const bke::greasepencil::Layer &src_layer = *src_layers[layer_i];
2258 bke::greasepencil::Layer &dst_layer = *dst_layers[layer_i];
2259 BKE_grease_pencil_copy_layer_parameters(src_layer, dst_layer);
2260
2261 dst_layer.set_name(src_layer.name());
2262 dst_layer.set_local_transform(task.transform * src_layer.local_transform());
2263
2264 const bke::greasepencil::Drawing *src_drawing = src_grease_pencil.get_eval_drawing(src_layer);
2265 if (!src_drawing) {
2266 continue;
2267 }
2268 bke::greasepencil::Drawing &dst_drawing = *dst_grease_pencil.get_eval_drawing(dst_layer);
2269
2270 const bke::CurvesGeometry &src_curves = src_drawing->strokes();
2271 bke::CurvesGeometry &dst_curves = dst_drawing.strokes_for_write();
2272 dst_curves = src_curves;
2273
2274 /* Remap materials. */
2275 bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
2276 bke::SpanAttributeWriter<int> material_indices =
2277 dst_attributes.lookup_or_add_for_write_span<int>("material_index", bke::AttrDomain::Curve);
2278 for (int &material_index : material_indices.span) {
2279 if (material_index >= 0 && material_index < src_grease_pencil.material_array_num) {
2280 material_index = grease_pencil_info.material_index_map[material_index];
2281 }
2282 }
2283 material_indices.finish();
2284 }
2285
2287 grease_pencil_info.attributes,
2289 ordered_attributes,
2290 [&](const bke::AttrDomain domain) {
2291 BLI_assert(domain == bke::AttrDomain::Layer);
2292 UNUSED_VARS_NDEBUG(domain);
2293 return dst_layers_slice;
2294 },
2295 dst_attribute_writers);
2296}
2297
2299 const float4x4 &transform)
2300{
2301 for (bke::greasepencil::Layer *layer : layers) {
2302 layer->set_local_transform(transform * layer->local_transform());
2303 }
2304}
2305
2307 const AllGreasePencilsInfo &all_grease_pencils_info,
2308 const GatherOffsets &offsets,
2310 const OrderedAttributes &ordered_attributes,
2311 RealizeInstancesResult &r_result)
2312{
2313 if (tasks.is_empty()) {
2314 return;
2315 }
2316
2317 if (tasks.size() == 1) {
2318 const RealizeGreasePencilTask &task = tasks.first();
2320 if (!skip_transform(task.transform)) {
2321 transform_grease_pencil_layers(new_gp->layers_for_write(), task.transform);
2322 }
2324 ordered_attributes, task.attribute_fallbacks, new_gp->attributes_for_write());
2325 r_result.geometry.replace_grease_pencil(new_gp);
2326 return;
2327 }
2328
2329 const int64_t new_layers_num = offsets.grease_pencil_layer_offset;
2330 if (!valid_int_num(new_layers_num)) {
2331 r_result.errors.append(RPT_("Realized grease pencil has too many layers."));
2332 return;
2333 }
2334
2335 /* Allocate new grease pencil. */
2336 GreasePencil *dst_grease_pencil = BKE_grease_pencil_new_nomain();
2337 BKE_grease_pencil_copy_parameters(*tasks.first().grease_pencil_info->grease_pencil,
2338 *dst_grease_pencil);
2339 r_result.geometry.replace_grease_pencil(dst_grease_pencil);
2340
2341 /* Allocate all layers. */
2342 dst_grease_pencil->add_layers_with_empty_drawings_for_eval(new_layers_num);
2343
2344 /* Transfer material pointers. The material indices are updated for each task separately. */
2345 if (!all_grease_pencils_info.materials.is_empty()) {
2346 MEM_SAFE_FREE(dst_grease_pencil->material_array);
2347 dst_grease_pencil->material_array_num = all_grease_pencils_info.materials.size();
2348 dst_grease_pencil->material_array = MEM_calloc_arrayN<Material *>(
2349 dst_grease_pencil->material_array_num, __func__);
2350 uninitialized_copy_n(all_grease_pencils_info.materials.data(),
2351 dst_grease_pencil->material_array_num,
2352 dst_grease_pencil->material_array);
2353 }
2354
2355 /* Prepare generic output attributes. */
2356 bke::MutableAttributeAccessor dst_attributes = dst_grease_pencil->attributes_for_write();
2357 Vector<GSpanAttributeWriter> dst_attribute_writers;
2358 for (const int attribute_index : ordered_attributes.index_range()) {
2359 const StringRef attribute_id = ordered_attributes.ids[attribute_index];
2360 const bke::AttrType data_type = ordered_attributes.kinds[attribute_index].data_type;
2361 dst_attribute_writers.append(dst_attributes.lookup_or_add_for_write_only_span(
2362 attribute_id, bke::AttrDomain::Layer, data_type));
2363 }
2364
2365 /* Actually execute all tasks. */
2366 threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
2367 for (const int task_index : task_range) {
2368 const RealizeGreasePencilTask &task = tasks[task_index];
2369 execute_realize_grease_pencil_task(
2370 task, ordered_attributes, *dst_grease_pencil, dst_attribute_writers);
2371 }
2372 });
2373
2374 /* Tag modified attributes. */
2375 for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
2376 dst_attribute.finish();
2377 }
2378}
2379/* -------------------------------------------------------------------- */
2382
2384 bke::GeometrySet &r_realized_geometry)
2385{
2386 if (tasks.is_empty()) {
2387 return;
2388 }
2389
2390 auto &component = r_realized_geometry.get_component_for_write<bke::GeometryComponentEditData>();
2391 for (const RealizeEditDataTask &task : tasks) {
2392 if (!component.curves_edit_hints_) {
2393 if (task.edit_data->curves_edit_hints_) {
2394 component.curves_edit_hints_ = std::make_unique<bke::CurvesEditHints>(
2395 *task.edit_data->curves_edit_hints_);
2396 }
2397 }
2398 if (const bke::GizmoEditHints *src_gizmo_edit_hints = task.edit_data->gizmo_edit_hints_.get())
2399 {
2400 if (!component.gizmo_edit_hints_) {
2401 component.gizmo_edit_hints_ = std::make_unique<bke::GizmoEditHints>();
2402 }
2403 for (auto item : src_gizmo_edit_hints->gizmo_transforms.items()) {
2404 component.gizmo_edit_hints_->gizmo_transforms.add(item.key, task.transform * item.value);
2405 }
2406 }
2407 }
2408}
2409
2411
2412/* -------------------------------------------------------------------- */
2415
2417{
2418 Instances *instances = geometry_set.get_instances_for_write();
2419 if (!instances) {
2420 return;
2421 }
2422 instances->attributes_for_write().remove("id");
2423 instances->ensure_geometry_instances();
2424 for (bke::InstanceReference &reference : instances->references_for_write()) {
2425 if (reference.type() == bke::InstanceReference::Type::GeometrySet) {
2427 }
2428 }
2429}
2430
2434static void propagate_instances_to_keep(const bke::GeometrySet &geometry_set,
2435 const IndexMask &selection,
2436 bke::GeometrySet &new_geometry_set,
2437 const bke::AttributeFilter &attribute_filter)
2438{
2439 const Instances &instances = *geometry_set.get_instances();
2440 IndexMaskMemory inverse_selection_indices;
2441 const IndexMask inverse_selection = selection.complement(IndexRange(instances.instances_num()),
2442 inverse_selection_indices);
2443 /* Check not all instances are being realized. */
2444 if (inverse_selection.is_empty()) {
2445 return;
2446 }
2447
2448 std::unique_ptr<Instances> new_instances = std::make_unique<Instances>(instances);
2449 new_instances->remove(inverse_selection, attribute_filter);
2450
2451 bke::InstancesComponent &new_instances_components =
2453 new_instances_components.replace(new_instances.release(), bke::GeometryOwnershipType::Owned);
2454}
2455
2458{
2459 if (!geometry_set.has_instances()) {
2460 return {geometry_set};
2461 }
2462
2463 VariedDepthOptions all_instances;
2465 geometry_set.get_instances()->instances_num());
2466 all_instances.selection = IndexMask(geometry_set.get_instances()->instances_num());
2467 return realize_instances(geometry_set, options, all_instances);
2468}
2469
2472 const VariedDepthOptions &varied_depth_option)
2473{
2474 /* The algorithm works in three steps:
2475 * 1. Preprocess each unique geometry that is instanced (e.g. each `Mesh`).
2476 * 2. Gather "tasks" that need to be executed to realize the instances. Each task corresponds
2477 * to instances of the previously preprocessed geometry.
2478 * 3. Execute all tasks in parallel.
2479 */
2480
2481 if (!geometry_set.has_instances()) {
2482 return {geometry_set};
2483 }
2484
2485 bke::GeometrySet not_to_realize_set;
2487 geometry_set, varied_depth_option.selection, not_to_realize_set, options.attribute_filter);
2488
2489 if (options.keep_original_ids) {
2491 }
2492
2493 AllPointCloudsInfo all_pointclouds_info = preprocess_pointclouds(
2494 geometry_set, options, varied_depth_option);
2495 AllMeshesInfo all_meshes_info = preprocess_meshes(geometry_set, options, varied_depth_option);
2496 AllCurvesInfo all_curves_info = preprocess_curves(geometry_set, options, varied_depth_option);
2497 AllGreasePencilsInfo all_grease_pencils_info = preprocess_grease_pencils(
2498 geometry_set, options, varied_depth_option);
2500 geometry_set, options, varied_depth_option);
2501
2502 const bool create_id_attribute = all_pointclouds_info.create_id_attribute ||
2503 all_meshes_info.create_id_attribute ||
2504 all_curves_info.create_id_attribute;
2505 Vector<std::unique_ptr<GArray<>>> temporary_arrays;
2506 GatherTasksInfo gather_info = {all_pointclouds_info,
2507 all_meshes_info,
2508 all_curves_info,
2509 all_grease_pencils_info,
2510 all_instance_attributes,
2511 create_id_attribute,
2512 varied_depth_option.selection,
2513 varied_depth_option.depths,
2514 temporary_arrays};
2515
2516 if (not_to_realize_set.has_instances()) {
2517 gather_info.instances.instances_components_to_merge.append(
2518 not_to_realize_set.get_component_for_write<bke::InstancesComponent>().copy());
2520 gather_info.instances.attribute_fallback.append(gather_info.instances_attriubutes.size());
2521 }
2522
2524 InstanceContext attribute_fallbacks(gather_info);
2525
2526 initialize_curves_builtin_attribute_defaults(all_curves_info, attribute_fallbacks);
2527
2529 gather_info, 0, VariedDepthOptions::MAX_DEPTH, geometry_set, transform, attribute_fallbacks);
2530
2534 all_instance_attributes,
2535 gather_info.instances.attribute_fallback,
2536 result.geometry);
2537
2538 const int64_t total_points_num = get_final_points_num(gather_info.r_tasks);
2539 /* This doesn't have to be exact at all, it's just a rough estimate to make decisions about
2540 * multi-threading (overhead). */
2541 const int64_t approximate_used_bytes_num = total_points_num * 32;
2542 threading::memory_bandwidth_bound_task(approximate_used_bytes_num, [&]() {
2544 gather_info.r_offsets,
2545 all_pointclouds_info,
2546 gather_info.r_tasks.pointcloud_tasks,
2547 all_pointclouds_info.attributes,
2548 result);
2550 gather_info.r_offsets,
2551 all_meshes_info,
2552 gather_info.r_tasks.mesh_tasks,
2553 all_meshes_info.attributes,
2554 all_meshes_info.materials,
2555 result);
2557 gather_info.r_offsets,
2558 all_curves_info,
2559 gather_info.r_tasks.curve_tasks,
2560 all_curves_info.attributes,
2561 result);
2562 execute_realize_grease_pencil_tasks(all_grease_pencils_info,
2563 gather_info.r_offsets,
2564 gather_info.r_tasks.grease_pencil_tasks,
2565 all_grease_pencils_info.attributes,
2566 result);
2568 });
2569 if (gather_info.r_tasks.first_volume) {
2570 result.geometry.add(*gather_info.r_tasks.first_volume);
2571 }
2572
2573 return result;
2574}
2575
2577
2578} // 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)
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(ID *id, int slot, 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_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
ATTR_WARN_UNUSED_RESULT const size_t num
#define ELEM(...)
#define RPT_(msgid)
#define CURVE_TYPES_NUM
@ CD_PROP_FLOAT2
Object is a sort of wrapper for general info.
#define MEM_SAFE_FREE(v)
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
IndexRange index_range() const
Definition BLI_array.hh:360
const T & first() const
Definition BLI_array.hh:281
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:419
AttributeSet attributes
constexpr bool contains(int64_t value) const
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:573
constexpr void fill(const T &value) const
Definition BLI_span.hh:517
constexpr T & last(const int64_t n=0) const
Definition BLI_span.hh:689
constexpr const T & first() const
Definition BLI_span.hh:315
constexpr bool is_empty() const
Definition BLI_span.hh:260
static VArray from_single(T value, const int64_t size)
static VArray from_span(Span< T > values)
const Key * data() const
bool add(const Key &key)
int64_t index_of_or_add(const Key &key)
const Key * begin() const
int64_t size() const
int64_t index_of(const Key &key) const
const Key * end() const
bool is_empty() const
Span< Key > as_span() const
void append(const T &value)
Span< T > as_span() const
Definition BLI_array.hh:243
void fill_assign_n(const void *value, void *dst, int64_t n) const
bool is() const
const void * default_value() const
GMutableSpan slice(const int64_t start, int64_t size) const
const CPPType & type() const
const CPPType * type() const
const void * get() const
Span< T > typed() const
const CPPType & type() const
int64_t size() const
static GVArray from_single(const CPPType &type, int64_t size, const void *value)
constexpr int64_t size() const
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:573
constexpr bool is_empty() const
Definition BLI_span.hh:509
constexpr void fill(const T &value) const
Definition BLI_span.hh:517
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:739
bool add_as(ForwardKey &&key)
Definition BLI_set.hh:256
bool contains(const Key &key) const
Definition BLI_set.hh:310
bool add(const Key &key)
Definition BLI_set.hh:248
constexpr const T & first() const
Definition BLI_span.hh:315
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
void copy_utf8_truncated(char *dst, int64_t dst_size) const
Definition string_ref.cc:28
std::optional< T > get_if_single() const
void materialize(MutableSpan< T > r_span) const
Span< T > get_internal_span() const
bool add(const Key &key)
int64_t size() const
int64_t size() const
void append(const T &value)
IndexRange index_range() const
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, AttrType data_type, const void *default_value=nullptr) const
bool is_builtin(const StringRef attribute_id) const
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
GPointer get_builtin_default(const StringRef attribute_id) const
bool contains(StringRef attribute_id) const
GAttributeReader lookup(const StringRef attribute_id) const
int domain_size(const AttrDomain domain) const
GAttributeReader get() const
MutableSpan< float3 > positions_for_write()
IndexRange curves_range() const
MutableAttributeAccessor attributes_for_write()
void nurbs_custom_knots_resize(int knots_num)
Span< float3 > positions() const
AttributeAccessor attributes() const
MutableSpan< int > offsets_for_write()
OffsetIndices< int > nurbs_custom_knots_by_curve() const
void convert_to_initialized_n(GSpan from_span, GMutableSpan to_span) const
bool is_convertible(const CPPType &from_type, const CPPType &to_type) const
int attribute_domain_size(AttrDomain domain) const
void to_geometry_set(GeometrySet &r_geometry_set) const
Definition instances.cc:94
GeometryComponentPtr copy() const override
void replace(Instances *instances, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
Span< int > reference_handles() const
Definition instances.cc:215
Span< float4x4 > transforms() const
Definition instances.cc:228
Span< InstanceReference > references() const
Definition instances.cc:275
bke::MutableAttributeAccessor attributes_for_write()
Definition instances.cc:69
bke::AttributeAccessor attributes() const
Definition instances.cc:64
MutableSpan< InstanceReference > references_for_write()
Definition instances.cc:280
int instances_num() const
Definition instances.cc:393
bool add(const StringRef attribute_id, const AttrDomain domain, const AttrType data_type, const AttributeInit &initializer)
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, AttrType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
bool remove(const StringRef attribute_id)
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, AttrType data_type)
bke::CurvesGeometry & strokes_for_write()
const bke::CurvesGeometry & strokes() const
void set_local_transform(const float4x4 &transform)
std::optional< bke::AttrDomain > result_domain
Definition BKE_mesh.hh:263
IndexMask complement(const IndexMask &universe, IndexMaskMemory &memory) const
void foreach_index(Fn &&fn) const
CCL_NAMESPACE_BEGIN struct Options options
static ushort indices[]
#define INT32_MAX
MatBase< 4, 4 > float4x4
MatBase< 3, 3 > float3x3
VecBase< short, 2 > short2
VecBase< float, 3 > float3
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void copy(const GVArray &src, GMutableSpan dst, int64_t grain_size=4096)
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
bool is_corner_fan_normals(const AttributeMetaData &meta_data)
void curves_copy_parameters(const Curves &src, Curves &dst)
ImplicitSharingPtr< GeometryComponent > GeometryComponentPtr
const DataTypeConversions & get_implicit_type_conversions()
bool attribute_is_builtin_on_component_type(const GeometryComponent::Type type, StringRef name)
void mesh_transform(Mesh &mesh, const float4x4 &transform, bool do_shape_keys)
AttrType cpp_type_to_attribute_type(const CPPType &type)
const CPPType & attribute_type_to_cpp_type(AttrType type)
Curves * curves_new_nomain(int points_num, int curves_num)
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 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_realize_curve_tasks(const RealizeInstancesOptions &options, const GatherOffsets &offsets, const AllCurvesInfo &all_curves_info, const Span< RealizeCurveTask > tasks, const OrderedAttributes &ordered_attributes, RealizeInstancesResult &r_result)
static void execute_realize_grease_pencil_tasks(const AllGreasePencilsInfo &all_grease_pencils_info, const GatherOffsets &offsets, const Span< RealizeGreasePencilTask > tasks, const OrderedAttributes &ordered_attributes, RealizeInstancesResult &r_result)
static void copy_vertex_group_name(ListBase *dst_deform_group, const OrderedAttributes &ordered_attributes, const bDeformGroup &src_deform_group)
static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options, const GatherOffsets &offsets, const AllMeshesInfo &all_meshes_info, const Span< RealizeMeshTask > tasks, const OrderedAttributes &ordered_attributes, const VectorSet< Material * > &ordered_materials, RealizeInstancesResult &r_result)
static void threaded_copy(const GSpan src, GMutableSpan dst)
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_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, GSpanAttributeWriter &all_dst_custom_normals)
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 initialize_curves_builtin_attribute_defaults(const AllCurvesInfo &all_curves_info, InstanceContext &attribute_fallbacks)
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)
static bool valid_int_num(const int64_t num)
void join_attributes(const Span< const bke::GeometryComponent * > src_components, bke::GeometryComponent &r_result, const Span< StringRef > ignored_attributes={})
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_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< float3 > all_custom_normals)
static bke::GeometrySet::GatheredAttributes gather_attributes_to_propagate(const bke::GeometrySet &geometry, const bke::GeometryComponent::Type component_type, const RealizeInstancesOptions &options, const VariedDepthOptions &varied_depth_option)
static void copy_vertex_group_names(Mesh &dst_mesh, const OrderedAttributes &ordered_attributes, const Span< const Mesh * > src_meshes)
RealizeInstancesResult realize_instances(bke::GeometrySet geometry_set, const RealizeInstancesOptions &options)
static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &options, const GatherOffsets &offsets, const AllPointCloudsInfo &all_pointclouds_info, const Span< RealizePointCloudTask > tasks, const OrderedAttributes &ordered_attributes, RealizeInstancesResult &r_result)
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)
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_instances_tasks(const Span< bke::GeometryComponentPtr > src_components, const Span< blender::float4x4 > src_base_transforms, const OrderedAttributes &all_instances_attributes, const Span< blender::geometry::AttributeFallbacksArray > attribute_fallback, bke::GeometrySet &r_realized_geometry)
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)
void transform_normals(const float3x3 &transform, MutableSpan< float3 > normals)
bool is_equal(const MatBase< T, NumCol, NumRow > &a, const MatBase< T, NumCol, NumRow > &b, const T epsilon=T(0))
void transform_points(const float4x4 &transform, MutableSpan< float3 > points, bool use_threading=true)
uint32_t hash(uint32_t kx)
Definition noise.cc:90
OffsetIndices< int > accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=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:93
void memory_bandwidth_bound_task(const int64_t approximate_bytes_touched, const Function &function)
Definition BLI_task.hh:265
MatBase< float, 4, 4 > float4x4
MatBase< float, 3, 3 > float3x3
VecBase< float, 3 > float3
blender::VecBase< int16_t, 2 > short2
void uninitialized_copy_n(const T *src, int64_t n, T *dst)
ListBase vertex_group_names
CurvesGeometry geometry
struct Material ** material_array
int corners_num
int edges_num
struct Material ** mat
CustomData corner_data
ListBase vertex_group_names
short totcol
int vertex_group_active_index
int faces_num
int verts_num
struct Material ** mat
bool allow_skip(const StringRef name) const
void add(const StringRef name, const AttributeDomainAndType &kind)
Vector< AttributeDomainAndType, 16 > kinds
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 replace_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
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
bke::mesh::NormalJoinInfo custom_normal_info
Array< MeshRealizeInfo > realize_info
Array< PointCloudRealizeInfo > realize_info
VectorSet< const PointCloud * > order
struct blender::geometry::GatherOffsets::@077126055320236227323125127266171230262045216140 mesh_offsets
struct blender::geometry::GatherOffsets::@336116134033231205014131370346202371156352227156 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
Vector< AttributeDomainAndType > kinds
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
i
Definition text_draw.cc:230
ParamHandle ** handles