Blender V4.5
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
26namespace blender::geometry {
27
29using blender::bke::AttributeDomainAndType;
30using blender::bke::GSpanAttributeWriter;
31using blender::bke::InstanceReference;
32using blender::bke::Instances;
33using blender::bke::SpanAttributeWriter;
34
42
43 int size() const
44 {
45 return this->kinds.size();
46 }
47
49 {
50 return this->kinds.index_range();
51 }
52};
53
65
75
87
90 int vertex = 0;
91 int edge = 0;
92 int face = 0;
93 int loop = 0;
94};
95
114
124
164
167 int point = 0;
168 int curve = 0;
169 int custom_knot = 0;
170};
171
182
190
198
203
214
228
230
233 enum class Output : int8_t { None, CornerFan, Free };
235 std::optional<bke::AttrDomain> result_domain;
236
238 {
239 this->add_domain(normal_domain_to_domain(domain));
240 }
241
243 {
245 if (this->result_type == Output::None) {
246 this->result_type = Output::CornerFan;
247 }
248 }
249
250 void add_domain(const bke::AttrDomain domain)
251 {
252 if (this->result_domain) {
253 /* Any combination of point/face domains puts the result normals on the corner domain. */
254 if (this->result_domain != domain) {
255 this->result_domain = bke::AttrDomain::Corner;
256 }
257 }
258 else {
259 this->result_domain = domain;
260 }
261 }
262
264 {
265 this->add_domain(domain);
266 this->result_type = Output::Free;
267 }
268
269 void add_mesh(const Mesh &mesh)
270 {
271 const bke::AttributeAccessor attributes = mesh.attributes();
272 const std::optional<bke::AttributeMetaData> custom_normal = attributes.lookup_meta_data(
273 "custom_normal");
274 if (!custom_normal) {
275 this->add_no_custom_normals(mesh.normals_domain());
276 return;
277 }
278 if (custom_normal->data_type == CD_PROP_FLOAT3) {
279 if (custom_normal->domain == bke::AttrDomain::Edge) {
280 /* Skip invalid storage on the edge domain. */
281 this->add_no_custom_normals(mesh.normals_domain());
282 return;
283 }
284 this->add_free_normals(custom_normal->domain);
285 }
286 else if (*custom_normal == CORNER_FAN_META_DATA) {
288 }
289 }
290};
291
310
323
334
343
356
364
395
411 uint32_t id = 0;
412
414 : pointclouds(gather_info.pointclouds.attributes.size()),
415 meshes(gather_info.meshes.attributes.size()),
416 curves(gather_info.curves.attributes.size()),
417 grease_pencils(gather_info.grease_pencils.attributes.size()),
418 instances(gather_info.instances_attriubutes.size())
419 {
420 // empty
421 }
422};
423
425{
426 int64_t points_num = 0;
427 if (!tasks.pointcloud_tasks.is_empty()) {
428 const RealizePointCloudTask &task = tasks.pointcloud_tasks.last();
429 points_num += task.start_index + task.pointcloud_info->pointcloud->totpoint;
430 }
431 if (!tasks.mesh_tasks.is_empty()) {
432 const RealizeMeshTask &task = tasks.mesh_tasks.last();
433 points_num += task.start_indices.vertex + task.mesh_info->mesh->verts_num;
434 }
435 if (!tasks.curve_tasks.is_empty()) {
436 const RealizeCurveTask &task = tasks.curve_tasks.last();
437 points_num += task.start_indices.point + task.curve_info->curves->geometry.point_num;
438 }
439 return points_num;
440}
441
443{
445}
446
448 const float4x4 &transform,
450{
452 dst.copy_from(src);
453 }
454 else {
455 threading::parallel_for(src.index_range(), 1024, [&](const IndexRange range) {
456 for (const int i : range) {
457 dst[i] = math::transform_point(transform, src[i]);
458 }
459 });
460 }
461}
462
464{
465 threading::parallel_for(positions.index_range(), 1024, [&](const IndexRange range) {
466 for (const int i : range) {
467 positions[i] = math::transform_point(transform, positions[i]);
468 }
469 });
470}
471
472static void threaded_copy(const GSpan src, GMutableSpan dst)
473{
474 BLI_assert(src.size() == dst.size());
475 BLI_assert(src.type() == dst.type());
476 threading::parallel_for(IndexRange(src.size()), 1024, [&](const IndexRange range) {
477 src.type().copy_construct_n(src.slice(range).data(), dst.slice(range).data(), range.size());
478 });
479}
480
481static void threaded_fill(const GPointer value, GMutableSpan dst)
482{
483 BLI_assert(*value.type() == dst.type());
484 threading::parallel_for(IndexRange(dst.size()), 1024, [&](const IndexRange range) {
485 value.type()->fill_construct_n(value.get(), dst.slice(range).data(), range.size());
486 });
487}
488
490 const Span<std::optional<GVArraySpan>> src_attributes,
491 const AttributeFallbacksArray &attribute_fallbacks,
492 const OrderedAttributes &ordered_attributes,
493 const FunctionRef<IndexRange(bke::AttrDomain)> &range_fn,
494 MutableSpan<GSpanAttributeWriter> dst_attribute_writers)
495{
497 dst_attribute_writers.index_range(), 10, [&](const IndexRange attribute_range) {
498 for (const int attribute_index : attribute_range) {
499 const bke::AttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
500 const IndexRange element_slice = range_fn(domain);
501
502 GSpanAttributeWriter &writer = dst_attribute_writers[attribute_index];
503 if (!writer) {
504 continue;
505 }
506 GMutableSpan dst_span = writer.span.slice(element_slice);
507 if (src_attributes[attribute_index].has_value()) {
508 threaded_copy(*src_attributes[attribute_index], dst_span);
509 }
510 else {
511 const CPPType &cpp_type = dst_span.type();
512 const void *fallback = attribute_fallbacks.array[attribute_index] == nullptr ?
513 cpp_type.default_value() :
514 attribute_fallbacks.array[attribute_index];
515 threaded_fill({cpp_type, fallback}, dst_span);
516 }
517 }
518 });
519}
520
522 const Span<int> stored_ids,
523 const int task_id,
524 MutableSpan<int> dst_ids)
525{
526 if (options.keep_original_ids) {
527 if (stored_ids.is_empty()) {
528 dst_ids.fill(0);
529 }
530 else {
531 dst_ids.copy_from(stored_ids);
532 }
533 }
534 else {
535 if (stored_ids.is_empty()) {
536 threading::parallel_for(dst_ids.index_range(), 1024, [&](const IndexRange range) {
537 for (const int i : range) {
538 dst_ids[i] = noise::hash(task_id, i);
539 }
540 });
541 }
542 else {
543 threading::parallel_for(dst_ids.index_range(), 1024, [&](const IndexRange range) {
544 for (const int i : range) {
545 dst_ids[i] = noise::hash(task_id, stored_ids[i]);
546 }
547 });
548 }
549 }
550}
551
552/* -------------------------------------------------------------------- */
555
556/* Forward declaration. */
557static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
558 const int current_depth,
559 const int target_depth,
560 const bke::GeometrySet &geometry_set,
561 const float4x4 &base_transform,
562 const InstanceContext &base_instance_context);
563
570 GatherTasksInfo &gather_info,
571 const Instances &instances,
572 const OrderedAttributes &ordered_attributes)
573{
574 Vector<std::pair<int, GSpan>> attributes_to_override;
575 const bke::AttributeAccessor attributes = instances.attributes();
576 attributes.foreach_attribute([&](const bke::AttributeIter &iter) {
577 const int attribute_index = ordered_attributes.ids.index_of_try(iter.name);
578 if (attribute_index == -1) {
579 /* The attribute is not propagated to the final geometry. */
580 return;
581 }
582 const bke::GAttributeReader attribute = iter.get();
583 if (!attribute || !attribute.varray.is_span()) {
584 return;
585 }
586 GSpan span = attribute.varray.get_internal_span();
587 const eCustomDataType expected_type = ordered_attributes.kinds[attribute_index].data_type;
588 if (iter.data_type != expected_type) {
589 const CPPType &from_type = span.type();
590 const CPPType &to_type = *bke::custom_data_type_to_cpp_type(expected_type);
592 if (!conversions.is_convertible(from_type, to_type)) {
593 /* Ignore the attribute because it can not be converted to the desired type. */
594 return;
595 }
596 /* Convert the attribute on the instances component to the expected attribute type. */
597 std::unique_ptr<GArray<>> temporary_array = std::make_unique<GArray<>>(
598 to_type, instances.instances_num());
599 conversions.convert_to_initialized_n(span, temporary_array->as_mutable_span());
600 span = temporary_array->as_span();
601 gather_info.r_temporary_arrays.append(std::move(temporary_array));
602 }
603 attributes_to_override.append({attribute_index, span});
604 });
605 return attributes_to_override;
606}
607
613 const InstanceReference &reference,
614 const float4x4 &base_transform,
615 const uint32_t id,
616 FunctionRef<void(const bke::GeometrySet &geometry_set, const float4x4 &transform, uint32_t id)>
617 fn)
618{
619 bke::GeometrySet geometry_set;
620 reference.to_geometry_set(geometry_set);
621 fn(geometry_set, base_transform, id);
622}
623
625 const int current_depth,
626 const int target_depth,
627 const Instances &instances,
628 const float4x4 &base_transform,
629 const InstanceContext &base_instance_context)
630{
631 const Span<InstanceReference> references = instances.references();
632 const Span<int> handles = instances.reference_handles();
633 const Span<float4x4> transforms = instances.transforms();
634
635 Span<int> stored_instance_ids;
636 if (gather_info.create_id_attribute_on_any_component) {
637 bke::AttributeReader ids = instances.attributes().lookup<int>("id");
638 if (ids) {
639 stored_instance_ids = ids.varray.get_internal_span();
640 }
641 }
642
643 /* Prepare attribute fallbacks. */
644 InstanceContext instance_context = base_instance_context;
645 Vector<std::pair<int, GSpan>> pointcloud_attributes_to_override = prepare_attribute_fallbacks(
646 gather_info, instances, gather_info.pointclouds.attributes);
647 Vector<std::pair<int, GSpan>> mesh_attributes_to_override = prepare_attribute_fallbacks(
648 gather_info, instances, gather_info.meshes.attributes);
649 Vector<std::pair<int, GSpan>> curve_attributes_to_override = prepare_attribute_fallbacks(
650 gather_info, instances, gather_info.curves.attributes);
651 Vector<std::pair<int, GSpan>> grease_pencil_attributes_to_override = prepare_attribute_fallbacks(
652 gather_info, instances, gather_info.grease_pencils.attributes);
653 Vector<std::pair<int, GSpan>> instance_attributes_to_override = prepare_attribute_fallbacks(
654 gather_info, instances, gather_info.instances_attriubutes);
655
656 const bool is_top_level = current_depth == 0;
657 /* If at top level, get instance indices from selection field, else use all instances. */
658 const IndexMask indices = is_top_level ? gather_info.selection :
659 IndexMask(IndexRange(instances.instances_num()));
660 indices.foreach_index([&](const int i) {
661 /* If at top level, retrieve depth from gather_info, else continue with target_depth. */
662 const int child_target_depth = is_top_level ? gather_info.depths[i] : target_depth;
663 const int handle = handles[i];
664 const float4x4 &transform = transforms[i];
665 const InstanceReference &reference = references[handle];
666 const float4x4 new_base_transform = base_transform * transform;
667
668 /* Update attribute fallbacks for the current instance. */
669 for (const std::pair<int, GSpan> &pair : pointcloud_attributes_to_override) {
670 instance_context.pointclouds.array[pair.first] = pair.second[i];
671 }
672 for (const std::pair<int, GSpan> &pair : mesh_attributes_to_override) {
673 instance_context.meshes.array[pair.first] = pair.second[i];
674 }
675 for (const std::pair<int, GSpan> &pair : curve_attributes_to_override) {
676 instance_context.curves.array[pair.first] = pair.second[i];
677 }
678 for (const std::pair<int, GSpan> &pair : grease_pencil_attributes_to_override) {
679 instance_context.grease_pencils.array[pair.first] = pair.second[i];
680 }
681 for (const std::pair<int, GSpan> &pair : instance_attributes_to_override) {
682 instance_context.instances.array[pair.first] = pair.second[i];
683 }
684
685 uint32_t local_instance_id = 0;
686 if (gather_info.create_id_attribute_on_any_component) {
687 if (stored_instance_ids.is_empty()) {
688 local_instance_id = uint32_t(i);
689 }
690 else {
691 local_instance_id = uint32_t(stored_instance_ids[i]);
692 }
693 }
694 const uint32_t instance_id = noise::hash(base_instance_context.id, local_instance_id);
695
696 /* Add realize tasks for all referenced geometry sets recursively. */
698 new_base_transform,
699 instance_id,
700 [&](const bke::GeometrySet &instance_geometry_set,
701 const float4x4 &transform,
702 const uint32_t id) {
703 instance_context.id = id;
705 current_depth + 1,
706 child_target_depth,
707 instance_geometry_set,
708 transform,
709 instance_context);
710 });
711 });
712}
713
718 const int current_depth,
719 const int target_depth,
720 const bke::GeometrySet &geometry_set,
721 const float4x4 &base_transform,
722 const InstanceContext &base_instance_context)
723{
724 for (const bke::GeometryComponent *component : geometry_set.get_components()) {
725 const bke::GeometryComponent::Type type = component->type();
726 switch (type) {
728 const Mesh *mesh = (*static_cast<const bke::MeshComponent *>(component)).get();
729 if (mesh != nullptr && mesh->verts_num > 0) {
730 const int mesh_index = gather_info.meshes.order.index_of(mesh);
731 const MeshRealizeInfo &mesh_info = gather_info.meshes.realize_info[mesh_index];
732 gather_info.r_tasks.mesh_tasks.append({gather_info.r_offsets.mesh_offsets,
733 &mesh_info,
734 base_transform,
735 base_instance_context.meshes,
736 base_instance_context.id});
737 gather_info.r_offsets.mesh_offsets.vertex += mesh->verts_num;
738 gather_info.r_offsets.mesh_offsets.edge += mesh->edges_num;
739 gather_info.r_offsets.mesh_offsets.loop += mesh->corners_num;
740 gather_info.r_offsets.mesh_offsets.face += mesh->faces_num;
741 }
742 break;
743 }
745 const auto &pointcloud_component = *static_cast<const bke::PointCloudComponent *>(
746 component);
747 const PointCloud *pointcloud = pointcloud_component.get();
748 if (pointcloud != nullptr && pointcloud->totpoint > 0) {
749 const int pointcloud_index = gather_info.pointclouds.order.index_of(pointcloud);
750 const PointCloudRealizeInfo &pointcloud_info =
751 gather_info.pointclouds.realize_info[pointcloud_index];
752 gather_info.r_tasks.pointcloud_tasks.append({gather_info.r_offsets.pointcloud_offset,
753 &pointcloud_info,
754 base_transform,
755 base_instance_context.pointclouds,
756 base_instance_context.id});
757 gather_info.r_offsets.pointcloud_offset += pointcloud->totpoint;
758 }
759 break;
760 }
762 const auto &curve_component = *static_cast<const bke::CurveComponent *>(component);
763 const Curves *curves = curve_component.get();
764 if (curves != nullptr && curves->geometry.curve_num > 0) {
765 const int curve_index = gather_info.curves.order.index_of(curves);
766 const RealizeCurveInfo &curve_info = gather_info.curves.realize_info[curve_index];
767 gather_info.r_tasks.curve_tasks.append({gather_info.r_offsets.curves_offsets,
768 &curve_info,
769 base_transform,
770 base_instance_context.curves,
771 base_instance_context.id});
772 gather_info.r_offsets.curves_offsets.point += curves->geometry.point_num;
773 gather_info.r_offsets.curves_offsets.curve += curves->geometry.curve_num;
775 }
776 break;
777 }
779 const auto &grease_pencil_component = *static_cast<const bke::GreasePencilComponent *>(
780 component);
781 const GreasePencil *grease_pencil = grease_pencil_component.get();
782 if (grease_pencil != nullptr && !grease_pencil->layers().is_empty()) {
783 const int grease_pencil_index = gather_info.grease_pencils.order.index_of(grease_pencil);
784 const GreasePencilRealizeInfo &grease_pencil_info =
785 gather_info.grease_pencils.realize_info[grease_pencil_index];
786 gather_info.r_tasks.grease_pencil_tasks.append(
788 &grease_pencil_info,
789 base_transform,
790 base_instance_context.grease_pencils});
791 gather_info.r_offsets.grease_pencil_layer_offset += grease_pencil->layers().size();
792 }
793 break;
794 }
796 if (current_depth == target_depth) {
797 gather_info.instances.attribute_fallback.append(base_instance_context.instances);
798 gather_info.instances.instances_components_to_merge.append(component->copy());
799 gather_info.instances.instances_components_transforms.append(base_transform);
800 }
801 else {
802 const Instances *instances =
803 (*static_cast<const bke::InstancesComponent *>(component)).get();
804 if (instances != nullptr && instances->instances_num() > 0) {
806 current_depth,
807 target_depth,
808 *instances,
809 base_transform,
810 base_instance_context);
811 }
812 }
813 break;
814 }
816 if (!gather_info.r_tasks.first_volume) {
817 const bke::VolumeComponent *volume_component = static_cast<const bke::VolumeComponent *>(
818 component);
819 volume_component->add_user();
821 volume_component);
822 }
823 break;
824 }
826 const auto *edit_component = static_cast<const bke::GeometryComponentEditData *>(
827 component);
828 if (edit_component->gizmo_edit_hints_ || edit_component->curves_edit_hints_) {
829 gather_info.r_tasks.edit_data_tasks.append({edit_component, base_transform});
830 }
831 break;
832 }
833 }
834 }
835}
836
839 const bke::GeometryComponent::Type component_type,
841 const int current_depth,
842 const std::optional<int> max_depth,
843 Set<bke::GeometryComponentPtr> &r_components)
844{
845 if (const bke::GeometryComponent *component = geometry.get_component(component_type)) {
846 if (r_components.add_as(component)) {
847 component->add_user();
848 }
849 }
850 if (current_depth == max_depth) {
851 return;
852 }
853 const auto *instances_component = geometry.get_component<bke::InstancesComponent>();
854 if (!instances_component) {
855 return;
856 }
857 const bke::Instances *instances = instances_component->get();
858 if (!instances) {
859 return;
860 }
861 if (options.realize_instance_attributes) {
862 if (r_components.add_as(instances_component)) {
863 instances_component->add_user();
864 }
865 }
866 for (const bke::InstanceReference &reference : instances->references()) {
867 bke::GeometrySet reference_geometry;
868 reference.to_geometry_set(reference_geometry);
870 reference_geometry, component_type, options, current_depth + 1, max_depth, r_components);
871 }
872}
873
876 const bke::GeometryComponent::Type component_type,
878 const VariedDepthOptions &varied_depth_option,
879 Set<bke::GeometryComponentPtr> &r_components)
880{
881 if (const bke::GeometryComponent *component = geometry.get_component(component_type)) {
882 if (r_components.add_as(component)) {
883 component->add_user();
884 }
885 }
886 const auto *instances_component = geometry.get_component<bke::InstancesComponent>();
887 if (!instances_component) {
888 return;
889 }
890 const bke::Instances *instances = instances_component->get();
891 if (!instances) {
892 return;
893 }
894
895 const Span<bke::InstanceReference> references = instances->references();
896 const Span<int> handles = instances->reference_handles();
897 const int references_num = references.size();
898 Array<std::optional<int>> max_reference_depth(references_num, 0);
899
900 varied_depth_option.selection.foreach_index([&](const int instance_i) {
901 const int reference_i = handles[instance_i];
902 const int instance_depth = varied_depth_option.depths[instance_i];
903 std::optional<int> &max_depth = max_reference_depth[reference_i];
904 if (!max_depth.has_value()) {
905 /* Is already at max depth. */
906 return;
907 }
908 if (instance_depth == VariedDepthOptions::MAX_DEPTH) {
909 max_depth.reset();
910 return;
911 }
912 max_depth = std::max<int>(*max_depth, instance_depth);
913 });
914
915 bool is_anything_realized = false;
916 for (const int reference_i : IndexRange(references_num)) {
917 const std::optional<int> max_depth = max_reference_depth[reference_i];
918 if (max_depth == 0) {
919 continue;
920 }
921 const bke::InstanceReference &reference = references[reference_i];
922 bke::GeometrySet reference_geometry;
923 reference.to_geometry_set(reference_geometry);
925 reference_geometry, component_type, options, 1, max_depth, r_components);
926 is_anything_realized = true;
927 }
928
929 if (is_anything_realized) {
930 if (options.realize_instance_attributes) {
931 if (r_components.add_as(instances_component)) {
932 instances_component->add_user();
933 }
934 }
935 }
936}
937
940 const bke::GeometryComponent::Type component_type,
942 const VariedDepthOptions &varied_depth_option)
943{
944 const bke::AttributeFilter &attribute_filter = options.attribute_filter;
945
946 const bke::InstancesComponent *top_level_instances_component =
947 geometry.get_component<bke::InstancesComponent>();
948 const int top_level_instances_num = top_level_instances_component ?
949 top_level_instances_component->attribute_domain_size(
950 AttrDomain::Instance) :
951 0;
952
953 /* Needs to take ownership because some components are only temporary otherwise. */
955 if (varied_depth_option.depths.get_if_single() == VariedDepthOptions::MAX_DEPTH &&
956 varied_depth_option.selection.size() == top_level_instances_num)
957 {
958 /* In this case we don't have to iterate over all instances, just over the references. */
960 geometry, component_type, options, 0, std::nullopt, components);
961 }
962 else {
964 geometry, component_type, options, varied_depth_option, components);
965 }
966
967 /* Actually gather the attributes to propagate from the found components. */
968 Map<StringRef, AttributeDomainAndType> attributes_to_propagate;
969 for (const bke::GeometryComponentPtr &component : components) {
970 const bke::AttributeAccessor attributes = *component->attributes();
971 attributes.foreach_attribute([&](const bke::AttributeIter &iter) {
972 if (iter.is_builtin) {
973 if (!bke::attribute_is_builtin_on_component_type(component_type, iter.name)) {
974 /* Don't propagate built-in attributes that are not built-in on the
975 * destination component. */
976 return;
977 }
978 }
979 if (component->type() == bke::GeometryComponent::Type::Instance) {
980 if (ELEM(iter.name, "instance_transform", ".reference_index")) {
981 /* These attributes reference potentially temporary instance components in the set above.
982 * If we added these names, the string references in the result map would outlive the
983 * attributes they reference. */
984 return;
985 }
986 }
987 if (iter.data_type == CD_PROP_STRING) {
988 /* Propagating string attributes is not supported yet. */
989 return;
990 }
991 if (attribute_filter.allow_skip(iter.name)) {
992 return;
993 }
994 AttrDomain dst_domain = iter.domain;
995 if (component_type != bke::GeometryComponent::Type::Instance &&
996 dst_domain == AttrDomain::Instance)
997 {
998 if (component_type == bke::GeometryComponent::Type::GreasePencil) {
999 /* For Grease Pencil, we want to propagate the instance attributes to the layers. */
1000 dst_domain = AttrDomain::Layer;
1001 }
1002 else {
1003 /* Other instance attributes are realized on the point domain currently. */
1004 dst_domain = AttrDomain::Point;
1005 }
1006 }
1007 auto add = [&](AttributeDomainAndType *kind) {
1008 kind->domain = dst_domain;
1009 kind->data_type = iter.data_type;
1010 };
1011 auto modify = [&](AttributeDomainAndType *kind) {
1012 kind->domain = bke::attribute_domain_highest_priority({kind->domain, dst_domain});
1014 {kind->data_type, iter.data_type});
1015 };
1016 attributes_to_propagate.add_or_modify(iter.name, add, modify);
1017 });
1018 }
1019
1020 return attributes_to_propagate;
1021}
1022
1024
1025/* -------------------------------------------------------------------- */
1028
1030 const bke::GeometrySet &in_geometry_set,
1032 const VariedDepthOptions &varied_depth_option)
1033{
1035 in_geometry_set, bke::GeometryComponent::Type::Instance, options, varied_depth_option);
1036 attributes_to_propagate.pop_try("id");
1037 OrderedAttributes ordered_attributes;
1038 for (const auto item : attributes_to_propagate.items()) {
1039 ordered_attributes.ids.add_new(item.key);
1040 ordered_attributes.kinds.append(item.value);
1041 }
1042 return ordered_attributes;
1043}
1044
1046 const Span<bke::GeometryComponentPtr> src_components,
1047 const Span<blender::float4x4> src_base_transforms,
1048 const OrderedAttributes &all_instances_attributes,
1049 const Span<blender::geometry::AttributeFallbacksArray> attribute_fallback,
1050 bke::GeometrySet &r_realized_geometry)
1051{
1052 BLI_assert(src_components.size() == src_base_transforms.size() &&
1053 src_components.size() == attribute_fallback.size());
1054 if (src_components.is_empty()) {
1055 return;
1056 }
1057
1058 Array<int> offsets_data(src_components.size() + 1);
1059 for (const int component_index : src_components.index_range()) {
1060 const bke::InstancesComponent &src_component = static_cast<const bke::InstancesComponent &>(
1061 *src_components[component_index]);
1062 offsets_data[component_index] = src_component.get()->instances_num();
1063 }
1064 const OffsetIndices offsets = offset_indices::accumulate_counts_to_offsets(offsets_data);
1065
1066 std::unique_ptr<bke::Instances> dst_instances = std::make_unique<bke::Instances>();
1067 dst_instances->resize(offsets.total_size());
1068
1069 /* Makes sure generic output attributes exists. */
1070 for (const int attribute_index : all_instances_attributes.index_range()) {
1072 const StringRef id = all_instances_attributes.ids[attribute_index];
1073 const eCustomDataType type = all_instances_attributes.kinds[attribute_index].data_type;
1074 dst_instances->attributes_for_write()
1075 .lookup_or_add_for_write_only_span(id, domain, type)
1076 .finish();
1077 }
1078
1079 MutableSpan<float4x4> all_transforms = dst_instances->transforms_for_write();
1080 MutableSpan<int> all_handles = dst_instances->reference_handles_for_write();
1081
1082 for (const int component_index : src_components.index_range()) {
1083 const bke::InstancesComponent &src_component = static_cast<const bke::InstancesComponent &>(
1084 *src_components[component_index]);
1085 const bke::Instances &src_instances = *src_component.get();
1086 const blender::float4x4 &src_base_transform = src_base_transforms[component_index];
1087 const Span<const void *> attribute_fallback_array = attribute_fallback[component_index].array;
1088 const Span<bke::InstanceReference> src_references = src_instances.references();
1089 Array<int> handle_map(src_references.size());
1090
1091 for (const int src_handle : src_references.index_range()) {
1092 handle_map[src_handle] = dst_instances->add_reference(src_references[src_handle]);
1093 }
1094 const IndexRange dst_range = offsets[component_index];
1095 for (const int attribute_index : all_instances_attributes.index_range()) {
1096 const StringRef id = all_instances_attributes.ids[attribute_index];
1097 const eCustomDataType type = all_instances_attributes.kinds[attribute_index].data_type;
1098 const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(type);
1099 BLI_assert(cpp_type != nullptr);
1100 bke::GSpanAttributeWriter write_attribute =
1101 dst_instances->attributes_for_write().lookup_for_write_span(id);
1102 GMutableSpan dst_span = write_attribute.span;
1103
1104 const void *attribute_ptr;
1105 if (attribute_fallback_array[attribute_index] != nullptr) {
1106 attribute_ptr = attribute_fallback_array[attribute_index];
1107 }
1108 else {
1109 attribute_ptr = cpp_type->default_value();
1110 }
1111
1112 cpp_type->fill_assign_n(attribute_ptr, dst_span.slice(dst_range).data(), dst_range.size());
1113 write_attribute.finish();
1114 }
1115
1116 const Span<int> src_handles = src_instances.reference_handles();
1117 array_utils::gather(handle_map.as_span(), src_handles, all_handles.slice(dst_range));
1118 array_utils::copy(src_instances.transforms(), all_transforms.slice(dst_range));
1119
1120 for (blender::float4x4 &transform : all_transforms.slice(dst_range)) {
1121 transform = src_base_transform * transform;
1122 }
1123 }
1124
1125 r_realized_geometry.replace_instances(dst_instances.release());
1126 auto &dst_component = r_realized_geometry.get_component_for_write<bke::InstancesComponent>();
1127
1128 Vector<const bke::GeometryComponent *> for_join_attributes;
1129 for (bke::GeometryComponentPtr component : src_components) {
1130 for_join_attributes.append(component.get());
1131 }
1132 /* Join attribute values from the 'unselected' instances, as they aren't included otherwise.
1133 * Omit instance_transform and .reference_index to prevent them from overwriting the correct
1134 * attributes of the realized instances. */
1135 join_attributes(for_join_attributes, dst_component, {".reference_index", "instance_transform"});
1136}
1137
1139
1140/* -------------------------------------------------------------------- */
1143
1145 const bke::GeometrySet &in_geometry_set,
1147 const VariedDepthOptions &varied_depth_option,
1148 bool &r_create_radii,
1149 bool &r_create_id)
1150{
1152 in_geometry_set, bke::GeometryComponent::Type::PointCloud, options, varied_depth_option);
1153 attributes_to_propagate.remove("position");
1154 r_create_id = attributes_to_propagate.pop_try("id").has_value();
1155 r_create_radii = attributes_to_propagate.pop_try("radius").has_value();
1156 OrderedAttributes ordered_attributes;
1157 for (const auto item : attributes_to_propagate.items()) {
1158 ordered_attributes.ids.add_new(item.key);
1159 ordered_attributes.kinds.append(item.value);
1160 }
1161 return ordered_attributes;
1162}
1163
1164static void gather_pointclouds_to_realize(const bke::GeometrySet &geometry_set,
1165 VectorSet<const PointCloud *> &r_pointclouds)
1166{
1167 if (const PointCloud *pointcloud = geometry_set.get_pointcloud()) {
1168 if (pointcloud->totpoint > 0) {
1169 r_pointclouds.add(pointcloud);
1170 }
1171 }
1172 if (const Instances *instances = geometry_set.get_instances()) {
1173 instances->foreach_referenced_geometry([&](const bke::GeometrySet &instance_geometry_set) {
1174 gather_pointclouds_to_realize(instance_geometry_set, r_pointclouds);
1175 });
1176 }
1177}
1178
1181 const VariedDepthOptions &varied_depth_option)
1182{
1183 AllPointCloudsInfo info;
1185 options,
1186 varied_depth_option,
1188 info.create_id_attribute);
1189
1190 gather_pointclouds_to_realize(geometry_set, info.order);
1191 info.realize_info.reinitialize(info.order.size());
1192 for (const int pointcloud_index : info.realize_info.index_range()) {
1193 PointCloudRealizeInfo &pointcloud_info = info.realize_info[pointcloud_index];
1194 const PointCloud *pointcloud = info.order[pointcloud_index];
1195 pointcloud_info.pointcloud = pointcloud;
1196
1197 /* Access attributes. */
1198 bke::AttributeAccessor attributes = pointcloud->attributes();
1199 pointcloud_info.attributes.reinitialize(info.attributes.size());
1200 for (const int attribute_index : info.attributes.index_range()) {
1201 const StringRef attribute_id = info.attributes.ids[attribute_index];
1202 const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
1203 const bke::AttrDomain domain = info.attributes.kinds[attribute_index].domain;
1204 if (attributes.contains(attribute_id)) {
1205 GVArray attribute = *attributes.lookup_or_default(attribute_id, domain, data_type);
1206 pointcloud_info.attributes[attribute_index].emplace(std::move(attribute));
1207 }
1208 }
1209 if (info.create_id_attribute) {
1210 bke::GAttributeReader ids_attribute = attributes.lookup("id");
1211 if (ids_attribute) {
1212 pointcloud_info.stored_ids = ids_attribute.varray.get_internal_span().typed<int>();
1213 }
1214 }
1215 if (info.create_radius_attribute) {
1216 pointcloud_info.radii = *attributes.lookup_or_default(
1217 "radius", bke::AttrDomain::Point, 0.01f);
1218 }
1219 const VArray<float3> position_attribute = *attributes.lookup_or_default<float3>(
1220 "position", bke::AttrDomain::Point, float3(0));
1221 pointcloud_info.positions = position_attribute.get_internal_span();
1222 }
1223 return info;
1224}
1225
1228 const RealizePointCloudTask &task,
1229 const OrderedAttributes &ordered_attributes,
1230 MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
1231 MutableSpan<float> all_dst_radii,
1232 MutableSpan<int> all_dst_ids,
1233 MutableSpan<float3> all_dst_positions)
1234{
1235 const PointCloudRealizeInfo &pointcloud_info = *task.pointcloud_info;
1236 const PointCloud &pointcloud = *pointcloud_info.pointcloud;
1237 const IndexRange point_slice{task.start_index, pointcloud.totpoint};
1238
1240 pointcloud_info.positions, task.transform, all_dst_positions.slice(point_slice));
1241
1242 /* Create point ids. */
1243 if (!all_dst_ids.is_empty()) {
1245 options, pointcloud_info.stored_ids, task.id, all_dst_ids.slice(point_slice));
1246 }
1247 if (!all_dst_radii.is_empty()) {
1248 pointcloud_info.radii.materialize(all_dst_radii.slice(point_slice));
1249 }
1250
1252 pointcloud_info.attributes,
1254 ordered_attributes,
1255 [&](const bke::AttrDomain domain) {
1256 BLI_assert(domain == bke::AttrDomain::Point);
1257 UNUSED_VARS_NDEBUG(domain);
1258 return point_slice;
1259 },
1260 dst_attribute_writers);
1261}
1262
1264 const OrderedAttributes &ordered_attributes,
1265 const AttributeFallbacksArray &attribute_fallbacks,
1267{
1268 for (const int attribute_index : ordered_attributes.index_range()) {
1269 const void *value = attribute_fallbacks.array[attribute_index];
1270 if (!value) {
1271 continue;
1272 }
1273 const bke::AttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
1274 const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
1275 const CPPType &cpp_type = *bke::custom_data_type_to_cpp_type(data_type);
1276 GVArray gvaray(GVArray::ForSingle(cpp_type, attributes.domain_size(domain), value));
1277 attributes.add(ordered_attributes.ids[attribute_index],
1278 domain,
1279 data_type,
1280 bke::AttributeInitVArray(std::move(gvaray)));
1281 }
1282}
1284 const AllPointCloudsInfo &all_pointclouds_info,
1285 const Span<RealizePointCloudTask> tasks,
1286 const OrderedAttributes &ordered_attributes,
1287 bke::GeometrySet &r_realized_geometry)
1288{
1289 if (tasks.is_empty()) {
1290 return;
1291 }
1292
1293 if (tasks.size() == 1) {
1294 const RealizePointCloudTask &task = tasks.first();
1296 if (!skip_transform(task.transform)) {
1297 transform_positions(task.transform, new_points->positions_for_write());
1298 new_points->tag_positions_changed();
1299 }
1301 ordered_attributes, task.attribute_fallbacks, new_points->attributes_for_write());
1302 r_realized_geometry.replace_pointcloud(new_points);
1303 return;
1304 }
1305
1306 const RealizePointCloudTask &last_task = tasks.last();
1307 const PointCloud &last_pointcloud = *last_task.pointcloud_info->pointcloud;
1308 const int tot_points = last_task.start_index + last_pointcloud.totpoint;
1309
1310 /* Allocate new point cloud. */
1311 PointCloud *dst_pointcloud = BKE_pointcloud_new_nomain(tot_points);
1312 r_realized_geometry.replace_pointcloud(dst_pointcloud);
1313 bke::MutableAttributeAccessor dst_attributes = dst_pointcloud->attributes_for_write();
1314
1315 const RealizePointCloudTask &first_task = tasks.first();
1316 const PointCloud &first_pointcloud = *first_task.pointcloud_info->pointcloud;
1317 dst_pointcloud->mat = static_cast<Material **>(MEM_dupallocN(first_pointcloud.mat));
1318 dst_pointcloud->totcol = first_pointcloud.totcol;
1319
1321 "position", bke::AttrDomain::Point);
1322
1323 /* Prepare id attribute. */
1324 SpanAttributeWriter<int> point_ids;
1325 if (all_pointclouds_info.create_id_attribute) {
1326 point_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id",
1328 }
1329 SpanAttributeWriter<float> point_radii;
1330 if (all_pointclouds_info.create_radius_attribute) {
1331 point_radii = dst_attributes.lookup_or_add_for_write_only_span<float>("radius",
1333 }
1334
1335 /* Prepare generic output attributes. */
1336 Vector<GSpanAttributeWriter> dst_attribute_writers;
1337 for (const int attribute_index : ordered_attributes.index_range()) {
1338 const StringRef attribute_id = ordered_attributes.ids[attribute_index];
1339 const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
1340 dst_attribute_writers.append(dst_attributes.lookup_or_add_for_write_only_span(
1341 attribute_id, bke::AttrDomain::Point, data_type));
1342 }
1343
1344 /* Actually execute all tasks. */
1345 threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
1346 for (const int task_index : task_range) {
1347 const RealizePointCloudTask &task = tasks[task_index];
1348 execute_realize_pointcloud_task(options,
1349 task,
1350 ordered_attributes,
1351 dst_attribute_writers,
1352 point_radii.span,
1353 point_ids.span,
1354 positions.span);
1355 }
1356 });
1357
1358 /* Tag modified attributes. */
1359 for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
1360 dst_attribute.finish();
1361 }
1362 positions.finish();
1363 point_radii.finish();
1364 point_ids.finish();
1365}
1366
1368
1369/* -------------------------------------------------------------------- */
1372
1374 const bke::GeometrySet &in_geometry_set,
1376 const VariedDepthOptions &varied_depth_option,
1377 bool &r_create_id,
1378 bool &r_create_material_index)
1379{
1381 in_geometry_set, bke::GeometryComponent::Type::Mesh, options, varied_depth_option);
1382 attributes_to_propagate.remove("position");
1383 attributes_to_propagate.remove(".edge_verts");
1384 attributes_to_propagate.remove(".corner_vert");
1385 attributes_to_propagate.remove(".corner_edge");
1386 attributes_to_propagate.remove("custom_normal");
1387 r_create_id = attributes_to_propagate.pop_try("id").has_value();
1388 r_create_material_index = attributes_to_propagate.pop_try("material_index").has_value();
1389 OrderedAttributes ordered_attributes;
1390 for (const auto item : attributes_to_propagate.items()) {
1391 ordered_attributes.ids.add_new(item.key);
1392 ordered_attributes.kinds.append(item.value);
1393 }
1394 return ordered_attributes;
1395}
1396
1397static void gather_meshes_to_realize(const bke::GeometrySet &geometry_set,
1398 VectorSet<const Mesh *> &r_meshes)
1399{
1400 if (const Mesh *mesh = geometry_set.get_mesh()) {
1401 if (mesh->verts_num > 0) {
1402 r_meshes.add(mesh);
1403 }
1404 }
1405 if (const Instances *instances = geometry_set.get_instances()) {
1406 instances->foreach_referenced_geometry([&](const bke::GeometrySet &instance_geometry_set) {
1407 gather_meshes_to_realize(instance_geometry_set, r_meshes);
1408 });
1409 }
1410}
1411
1414 const VariedDepthOptions &varied_depth_option)
1415{
1416 AllMeshesInfo info;
1418 geometry_set,
1419 options,
1420 varied_depth_option,
1423
1424 gather_meshes_to_realize(geometry_set, info.order);
1425 for (const Mesh *mesh : info.order) {
1426 if (mesh->totcol == 0) {
1427 /* Add an empty material slot for the default material. */
1428 info.materials.add(nullptr);
1429 }
1430 else {
1431 for (const int slot_index : IndexRange(mesh->totcol)) {
1432 Material *material = mesh->mat[slot_index];
1433 info.materials.add(material);
1434 }
1435 }
1436 }
1437
1438 for (const Mesh *mesh : info.order) {
1439 info.custom_normal_info.add_mesh(*mesh);
1440 }
1441
1443 info.realize_info.reinitialize(info.order.size());
1444 for (const int mesh_index : info.realize_info.index_range()) {
1445 MeshRealizeInfo &mesh_info = info.realize_info[mesh_index];
1446 const Mesh *mesh = info.order[mesh_index];
1447 mesh_info.mesh = mesh;
1448 mesh_info.positions = mesh->vert_positions();
1449 mesh_info.edges = mesh->edges();
1450 mesh_info.faces = mesh->faces();
1451 mesh_info.corner_verts = mesh->corner_verts();
1452 mesh_info.corner_edges = mesh->corner_edges();
1453
1454 /* Create material index mapping. */
1455 mesh_info.material_index_map.reinitialize(std::max<int>(mesh->totcol, 1));
1456 if (mesh->totcol == 0) {
1457 mesh_info.material_index_map.first() = info.materials.index_of(nullptr);
1458 }
1459 else {
1460 for (const int old_slot_index : IndexRange(mesh->totcol)) {
1461 Material *material = mesh->mat[old_slot_index];
1462 const int new_slot_index = info.materials.index_of(material);
1463 mesh_info.material_index_map[old_slot_index] = new_slot_index;
1464 }
1465 }
1466
1467 /* Access attributes. */
1468 bke::AttributeAccessor attributes = mesh->attributes();
1469 mesh_info.attributes.reinitialize(info.attributes.size());
1470 for (const int attribute_index : info.attributes.index_range()) {
1471 const StringRef attribute_id = info.attributes.ids[attribute_index];
1472 const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
1473 const bke::AttrDomain domain = info.attributes.kinds[attribute_index].domain;
1474 if (attributes.contains(attribute_id)) {
1475 GVArray attribute = *attributes.lookup_or_default(attribute_id, domain, data_type);
1476 mesh_info.attributes[attribute_index].emplace(std::move(attribute));
1477 }
1478 }
1479 if (info.create_id_attribute) {
1480 bke::GAttributeReader ids_attribute = attributes.lookup("id");
1481 if (ids_attribute) {
1482 mesh_info.stored_vertex_ids = ids_attribute.varray.get_internal_span().typed<int>();
1483 }
1484 }
1485 mesh_info.material_indices = *attributes.lookup_or_default<int>(
1486 "material_index", bke::AttrDomain::Face, 0);
1487
1488 switch (info.custom_normal_info.result_type) {
1490 break;
1491 }
1493 if (attributes.lookup_meta_data("custom_normal") == CORNER_FAN_META_DATA) {
1494 mesh_info.custom_normal = *attributes.lookup<short2>("custom_normal",
1496 }
1497 break;
1498 }
1500 switch (*info.custom_normal_info.result_domain) {
1502 mesh_info.custom_normal = VArray<float3>::ForSpan(mesh->vert_normals());
1503 break;
1505 mesh_info.custom_normal = VArray<float3>::ForSpan(mesh->face_normals());
1506 break;
1508 mesh_info.custom_normal = VArray<float3>::ForSpan(mesh->corner_normals());
1509 break;
1510 default:
1512 }
1513 break;
1514 }
1515 }
1516 }
1517
1518 info.no_loose_edges_hint = std::all_of(
1519 info.order.begin(), info.order.end(), [](const Mesh *mesh) {
1520 return mesh->runtime->loose_edges_cache.is_cached() && mesh->loose_edges().count == 0;
1521 });
1522 info.no_loose_verts_hint = std::all_of(
1523 info.order.begin(), info.order.end(), [](const Mesh *mesh) {
1524 return mesh->runtime->loose_verts_cache.is_cached() && mesh->loose_verts().count == 0;
1525 });
1526 info.no_overlapping_hint = std::all_of(
1527 info.order.begin(), info.order.end(), [](const Mesh *mesh) {
1528 return mesh->no_overlapping_topology();
1529 });
1530
1531 return info;
1532}
1533
1535 const RealizeMeshTask &task,
1536 const OrderedAttributes &ordered_attributes,
1537 MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
1538 MutableSpan<float3> all_dst_positions,
1539 MutableSpan<int2> all_dst_edges,
1540 MutableSpan<int> all_dst_face_offsets,
1541 MutableSpan<int> all_dst_corner_verts,
1542 MutableSpan<int> all_dst_corner_edges,
1543 MutableSpan<int> all_dst_vertex_ids,
1544 MutableSpan<int> all_dst_material_indices,
1545 GSpanAttributeWriter &all_dst_custom_normals)
1546{
1547 const MeshRealizeInfo &mesh_info = *task.mesh_info;
1548 const Mesh &mesh = *mesh_info.mesh;
1549
1550 const Span<float3> src_positions = mesh_info.positions;
1551 const Span<int2> src_edges = mesh_info.edges;
1552 const OffsetIndices src_faces = mesh_info.faces;
1553 const Span<int> src_corner_verts = mesh_info.corner_verts;
1554 const Span<int> src_corner_edges = mesh_info.corner_edges;
1555
1556 const IndexRange dst_vert_range(task.start_indices.vertex, src_positions.size());
1557 const IndexRange dst_edge_range(task.start_indices.edge, src_edges.size());
1558 const IndexRange dst_face_range(task.start_indices.face, src_faces.size());
1559 const IndexRange dst_loop_range(task.start_indices.loop, src_corner_verts.size());
1560
1561 MutableSpan<float3> dst_positions = all_dst_positions.slice(dst_vert_range);
1562 MutableSpan<int2> dst_edges = all_dst_edges.slice(dst_edge_range);
1563 MutableSpan<int> dst_face_offsets = all_dst_face_offsets.slice(dst_face_range);
1564 MutableSpan<int> dst_corner_verts = all_dst_corner_verts.slice(dst_loop_range);
1565 MutableSpan<int> dst_corner_edges = all_dst_corner_edges.slice(dst_loop_range);
1566
1567 threading::parallel_for(src_positions.index_range(), 1024, [&](const IndexRange vert_range) {
1568 for (const int i : vert_range) {
1569 dst_positions[i] = math::transform_point(task.transform, src_positions[i]);
1570 }
1571 });
1572 threading::parallel_for(src_edges.index_range(), 1024, [&](const IndexRange edge_range) {
1573 for (const int i : edge_range) {
1574 dst_edges[i] = src_edges[i] + task.start_indices.vertex;
1575 }
1576 });
1577 threading::parallel_for(src_corner_verts.index_range(), 1024, [&](const IndexRange loop_range) {
1578 for (const int i : loop_range) {
1579 dst_corner_verts[i] = src_corner_verts[i] + task.start_indices.vertex;
1580 }
1581 });
1582 threading::parallel_for(src_corner_edges.index_range(), 1024, [&](const IndexRange loop_range) {
1583 for (const int i : loop_range) {
1584 dst_corner_edges[i] = src_corner_edges[i] + task.start_indices.edge;
1585 }
1586 });
1587 threading::parallel_for(src_faces.index_range(), 1024, [&](const IndexRange face_range) {
1588 for (const int i : face_range) {
1589 dst_face_offsets[i] = src_faces[i].start() + task.start_indices.loop;
1590 }
1591 });
1592 if (!all_dst_material_indices.is_empty()) {
1593 const Span<int> material_index_map = mesh_info.material_index_map;
1594 MutableSpan<int> dst_material_indices = all_dst_material_indices.slice(dst_face_range);
1595 if (mesh.totcol == 0) {
1596 /* The material index map contains the index of the null material in the result. */
1597 dst_material_indices.fill(material_index_map.first());
1598 }
1599 else {
1600 if (mesh_info.material_indices.is_single()) {
1601 const int src_index = mesh_info.material_indices.get_internal_single();
1602 const bool valid = IndexRange(mesh.totcol).contains(src_index);
1603 dst_material_indices.fill(valid ? material_index_map[src_index] : 0);
1604 }
1605 else {
1606 VArraySpan<int> indices_span(mesh_info.material_indices);
1607 threading::parallel_for(src_faces.index_range(), 1024, [&](const IndexRange face_range) {
1608 for (const int i : face_range) {
1609 const int src_index = indices_span[i];
1610 const bool valid = IndexRange(mesh.totcol).contains(src_index);
1611 dst_material_indices[i] = valid ? material_index_map[src_index] : 0;
1612 }
1613 });
1614 }
1615 }
1616 }
1617
1618 if (!all_dst_vertex_ids.is_empty()) {
1620 mesh_info.stored_vertex_ids,
1621 task.id,
1622 all_dst_vertex_ids.slice(task.start_indices.vertex, mesh.verts_num));
1623 }
1624
1625 const auto domain_to_range = [&](const bke::AttrDomain domain) {
1626 switch (domain) {
1627 case bke::AttrDomain::Point:
1628 return dst_vert_range;
1629 case bke::AttrDomain::Edge:
1630 return dst_edge_range;
1631 case bke::AttrDomain::Face:
1632 return dst_face_range;
1633 case bke::AttrDomain::Corner:
1634 return dst_loop_range;
1635 default:
1637 return IndexRange();
1638 }
1639 };
1640
1641 if (all_dst_custom_normals) {
1642 if (all_dst_custom_normals.span.type().is<short2>()) {
1643 if (mesh_info.custom_normal.is_empty()) {
1644 all_dst_custom_normals.span.typed<short2>().slice(dst_loop_range).fill(short2(0));
1645 }
1646 else {
1647 all_dst_custom_normals.span.typed<short2>()
1648 .slice(dst_loop_range)
1649 .copy_from(mesh_info.custom_normal.typed<short2>());
1650 }
1651 }
1652 else {
1653 const IndexRange dst_range = domain_to_range(all_dst_custom_normals.domain);
1654 math::transform_normals(mesh_info.custom_normal.typed<float3>(),
1655 float3x3(task.transform),
1656 all_dst_custom_normals.span.typed<float3>().slice(dst_range));
1657 }
1658 }
1659
1660 copy_generic_attributes_to_result(mesh_info.attributes,
1661 task.attribute_fallbacks,
1662 ordered_attributes,
1663 domain_to_range,
1664 dst_attribute_writers);
1665}
1666static void copy_vertex_group_name(ListBase *dst_deform_group,
1667 const OrderedAttributes &ordered_attributes,
1668 const bDeformGroup &src_deform_group)
1669{
1670 const StringRef src_name = src_deform_group.name;
1671 const int attribute_index = ordered_attributes.ids.index_of_try(src_name);
1672 if (attribute_index == -1) {
1673 /* The attribute is not propagated to the result (possibly because the mesh isn't included
1674 * in the realized output because of the #VariedDepthOptions input). */
1675 return;
1676 }
1677 const bke::AttributeDomainAndType kind = ordered_attributes.kinds[attribute_index];
1678 if (kind.domain != bke::AttrDomain::Point || kind.data_type != CD_PROP_FLOAT) {
1679 /* Skip if the source attribute can't possibly contain vertex weights. */
1680 return;
1681 }
1682 bDeformGroup *dst = MEM_callocN<bDeformGroup>(__func__);
1683 src_name.copy_utf8_truncated(dst->name);
1684 BLI_addtail(dst_deform_group, dst);
1685}
1686
1687static void copy_vertex_group_names(Mesh &dst_mesh,
1688 const OrderedAttributes &ordered_attributes,
1689 const Span<const Mesh *> src_meshes)
1690{
1691 Set<StringRef> existing_names;
1692 LISTBASE_FOREACH (const bDeformGroup *, defgroup, &dst_mesh.vertex_group_names) {
1693 existing_names.add(defgroup->name);
1694 }
1695 for (const Mesh *mesh : src_meshes) {
1696 LISTBASE_FOREACH (const bDeformGroup *, src, &mesh->vertex_group_names) {
1697 if (existing_names.contains(src->name)) {
1698 continue;
1699 }
1700 copy_vertex_group_name(&dst_mesh.vertex_group_names, ordered_attributes, *src);
1701 }
1702 }
1703}
1704
1706 const AllMeshesInfo &all_meshes_info,
1707 const Span<RealizeMeshTask> tasks,
1708 const OrderedAttributes &ordered_attributes,
1709 const VectorSet<Material *> &ordered_materials,
1710 bke::GeometrySet &r_realized_geometry)
1711{
1712 if (tasks.is_empty()) {
1713 return;
1714 }
1715
1716 if (tasks.size() == 1) {
1717 const RealizeMeshTask &task = tasks.first();
1718 Mesh *new_mesh = BKE_mesh_copy_for_eval(*task.mesh_info->mesh);
1719 if (!skip_transform(task.transform)) {
1720 bke::mesh_transform(*new_mesh, task.transform, false);
1721 }
1723 ordered_attributes, task.attribute_fallbacks, new_mesh->attributes_for_write());
1724 r_realized_geometry.replace_mesh(new_mesh);
1725 return;
1726 }
1727
1728 const RealizeMeshTask &last_task = tasks.last();
1729 const Mesh &last_mesh = *last_task.mesh_info->mesh;
1730 const int tot_vertices = last_task.start_indices.vertex + last_mesh.verts_num;
1731 const int tot_edges = last_task.start_indices.edge + last_mesh.edges_num;
1732 const int tot_loops = last_task.start_indices.loop + last_mesh.corners_num;
1733 const int tot_faces = last_task.start_indices.face + last_mesh.faces_num;
1734
1735 Mesh *dst_mesh = BKE_mesh_new_nomain(tot_vertices, tot_edges, tot_faces, tot_loops);
1736 r_realized_geometry.replace_mesh(dst_mesh);
1737 bke::MutableAttributeAccessor dst_attributes = dst_mesh->attributes_for_write();
1738 MutableSpan<float3> dst_positions = dst_mesh->vert_positions_for_write();
1739 MutableSpan<int2> dst_edges = dst_mesh->edges_for_write();
1740 MutableSpan<int> dst_face_offsets = dst_mesh->face_offsets_for_write();
1741 MutableSpan<int> dst_corner_verts = dst_mesh->corner_verts_for_write();
1742 MutableSpan<int> dst_corner_edges = dst_mesh->corner_edges_for_write();
1743
1744 /* Copy settings from the first input geometry set with a mesh. */
1745 const RealizeMeshTask &first_task = tasks.first();
1746 const Mesh &first_mesh = *first_task.mesh_info->mesh;
1747 BKE_mesh_copy_parameters_for_eval(dst_mesh, &first_mesh);
1748
1752 *dst_mesh, ordered_attributes, all_meshes_info.order.as_span().drop_front(1));
1754
1755 /* Add materials. */
1756 for (const int i : IndexRange(ordered_materials.size())) {
1757 Material *material = ordered_materials[i];
1758 BKE_id_material_eval_assign(&dst_mesh->id, i + 1, material);
1759 }
1760
1761 /* Prepare id attribute. */
1762 SpanAttributeWriter<int> vertex_ids;
1763 if (all_meshes_info.create_id_attribute) {
1764 vertex_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id",
1766 }
1767 /* Prepare material indices. */
1768 SpanAttributeWriter<int> material_indices;
1769 if (all_meshes_info.create_material_index_attribute) {
1770 material_indices = dst_attributes.lookup_or_add_for_write_only_span<int>(
1771 "material_index", bke::AttrDomain::Face);
1772 }
1773
1774 GSpanAttributeWriter custom_normals;
1775 switch (all_meshes_info.custom_normal_info.result_type) {
1777 break;
1778 }
1780 custom_normals = dst_attributes.lookup_or_add_for_write_only_span(
1781 "custom_normal", bke::AttrDomain::Corner, CD_PROP_INT16_2D);
1782 break;
1783 }
1785 const bke::AttrDomain domain = *all_meshes_info.custom_normal_info.result_domain;
1786 custom_normals = dst_attributes.lookup_or_add_for_write_only_span(
1787 "custom_normal", domain, CD_PROP_FLOAT3);
1788 break;
1789 }
1790 }
1791
1792 /* Prepare generic output attributes. */
1793 Vector<GSpanAttributeWriter> dst_attribute_writers;
1794 for (const int attribute_index : ordered_attributes.index_range()) {
1795 const StringRef attribute_id = ordered_attributes.ids[attribute_index];
1796 const bke::AttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
1797 const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
1798 dst_attribute_writers.append(
1799 dst_attributes.lookup_or_add_for_write_only_span(attribute_id, domain, data_type));
1800 }
1801 const char *active_layer = CustomData_get_active_layer_name(&first_mesh.corner_data,
1803 if (active_layer != nullptr) {
1804 int id = CustomData_get_named_layer(&dst_mesh->corner_data, CD_PROP_FLOAT2, active_layer);
1805 if (id >= 0) {
1807 }
1808 }
1809 const char *render_layer = CustomData_get_render_layer_name(&first_mesh.corner_data,
1811 if (render_layer != nullptr) {
1812 int id = CustomData_get_named_layer(&dst_mesh->corner_data, CD_PROP_FLOAT2, render_layer);
1813 if (id >= 0) {
1815 }
1816 }
1817 /* Actually execute all tasks. */
1818 threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
1819 for (const int task_index : task_range) {
1820 const RealizeMeshTask &task = tasks[task_index];
1821 execute_realize_mesh_task(options,
1822 task,
1823 ordered_attributes,
1824 dst_attribute_writers,
1825 dst_positions,
1826 dst_edges,
1827 dst_face_offsets,
1828 dst_corner_verts,
1829 dst_corner_edges,
1830 vertex_ids.span,
1831 material_indices.span,
1832 custom_normals);
1833 }
1834 });
1835
1836 /* Tag modified attributes. */
1837 for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
1838 dst_attribute.finish();
1839 }
1840 vertex_ids.finish();
1841 material_indices.finish();
1842 custom_normals.finish();
1843
1844 if (all_meshes_info.no_loose_edges_hint) {
1845 dst_mesh->tag_loose_edges_none();
1846 }
1847 if (all_meshes_info.no_loose_verts_hint) {
1848 dst_mesh->tag_loose_verts_none();
1849 }
1850 if (all_meshes_info.no_overlapping_hint) {
1851 dst_mesh->tag_overlapping_none();
1852 }
1853}
1854
1856
1857/* -------------------------------------------------------------------- */
1860
1862 const bke::GeometrySet &in_geometry_set,
1864 const VariedDepthOptions &varied_depth_option,
1865 bool &r_create_id)
1866{
1868 in_geometry_set, bke::GeometryComponent::Type::Curve, options, varied_depth_option);
1869 attributes_to_propagate.remove("position");
1870 attributes_to_propagate.remove("radius");
1871 attributes_to_propagate.remove("handle_right");
1872 attributes_to_propagate.remove("handle_left");
1873 attributes_to_propagate.remove("custom_normal");
1874 r_create_id = attributes_to_propagate.pop_try("id").has_value();
1875 OrderedAttributes ordered_attributes;
1876 for (const auto item : attributes_to_propagate.items()) {
1877 ordered_attributes.ids.add_new(item.key);
1878 ordered_attributes.kinds.append(item.value);
1879 }
1880 return ordered_attributes;
1881}
1882
1883static void gather_curves_to_realize(const bke::GeometrySet &geometry_set,
1884 VectorSet<const Curves *> &r_curves)
1885{
1886 if (const Curves *curves = geometry_set.get_curves()) {
1887 if (curves->geometry.curve_num != 0) {
1888 r_curves.add(curves);
1889 }
1890 }
1891 if (const Instances *instances = geometry_set.get_instances()) {
1892 instances->foreach_referenced_geometry([&](const bke::GeometrySet &instance_geometry_set) {
1893 gather_curves_to_realize(instance_geometry_set, r_curves);
1894 });
1895 }
1896}
1897
1900 const VariedDepthOptions &varied_depth_option)
1901{
1902 AllCurvesInfo info;
1904 geometry_set, options, varied_depth_option, info.create_id_attribute);
1905
1906 gather_curves_to_realize(geometry_set, info.order);
1907 info.realize_info.reinitialize(info.order.size());
1908 for (const int curve_index : info.realize_info.index_range()) {
1909 RealizeCurveInfo &curve_info = info.realize_info[curve_index];
1910 const Curves *curves_id = info.order[curve_index];
1911 const bke::CurvesGeometry &curves = curves_id->geometry.wrap();
1912 curve_info.curves = curves_id;
1913
1914 /* Access attributes. */
1915 bke::AttributeAccessor attributes = curves.attributes();
1916 curve_info.attributes.reinitialize(info.attributes.size());
1917 for (const int attribute_index : info.attributes.index_range()) {
1918 const bke::AttrDomain domain = info.attributes.kinds[attribute_index].domain;
1919 const StringRef attribute_id = info.attributes.ids[attribute_index];
1920 const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
1921 if (attributes.contains(attribute_id)) {
1922 GVArray attribute = *attributes.lookup_or_default(attribute_id, domain, data_type);
1923 curve_info.attributes[attribute_index].emplace(std::move(attribute));
1924 }
1925 }
1926 if (info.create_id_attribute) {
1927 bke::GAttributeReader id_attribute = attributes.lookup("id");
1928 if (id_attribute) {
1929 curve_info.stored_ids = id_attribute.varray.get_internal_span().typed<int>();
1930 }
1931 }
1932
1933 if (attributes.contains("radius")) {
1934 curve_info.radius =
1935 attributes.lookup<float>("radius", bke::AttrDomain::Point).varray.get_internal_span();
1936 info.create_radius_attribute = true;
1937 }
1938 if (attributes.contains("handle_right")) {
1939 curve_info.handle_left = attributes.lookup<float3>("handle_left", bke::AttrDomain::Point)
1940 .varray.get_internal_span();
1941 curve_info.handle_right = attributes.lookup<float3>("handle_right", bke::AttrDomain::Point)
1942 .varray.get_internal_span();
1944 }
1945 if (attributes.contains("custom_normal")) {
1946 curve_info.custom_normal = attributes.lookup<float3>("custom_normal", bke::AttrDomain::Point)
1947 .varray.get_internal_span();
1949 }
1950 }
1951 return info;
1952}
1953
1955 InstanceContext &attribute_fallbacks)
1956{
1957 if (all_curves_info.order.is_empty()) {
1958 return;
1959 }
1960 const Curves *first = all_curves_info.order[0];
1961 const bke::CurvesGeometry &first_curves = first->geometry.wrap();
1962 for (const int attribute_i : attribute_fallbacks.curves.array.index_range()) {
1963 const StringRef attribute_id = all_curves_info.attributes.ids[attribute_i];
1964 if (first_curves.attributes().is_builtin(attribute_id)) {
1965 attribute_fallbacks.curves.array[attribute_i] =
1966 first_curves.attributes().get_builtin_default(attribute_id).get();
1967 }
1968 }
1969}
1970
1972 const AllCurvesInfo &all_curves_info,
1973 const RealizeCurveTask &task,
1974 const OrderedAttributes &ordered_attributes,
1975 bke::CurvesGeometry &dst_curves,
1976 MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
1977 MutableSpan<int> all_dst_ids,
1978 MutableSpan<float3> all_handle_left,
1979 MutableSpan<float3> all_handle_right,
1980 MutableSpan<float> all_radii,
1981 MutableSpan<float3> all_custom_normals)
1982{
1983 const RealizeCurveInfo &curves_info = *task.curve_info;
1984 const Curves &curves_id = *curves_info.curves;
1985 const bke::CurvesGeometry &curves = curves_id.geometry.wrap();
1986
1987 const IndexRange dst_point_range{task.start_indices.point, curves.points_num()};
1988 const IndexRange dst_curve_range{task.start_indices.curve, curves.curves_num()};
1989 const IndexRange dst_custom_knot_range{task.start_indices.custom_knot,
1990 curves.nurbs_custom_knots_by_curve().total_size()};
1991
1993 curves.positions(), task.transform, dst_curves.positions_for_write().slice(dst_point_range));
1994
1995 /* Copy and transform handle positions if necessary. */
1996 if (all_curves_info.create_handle_postion_attributes) {
1997 if (curves_info.handle_left.is_empty()) {
1998 all_handle_left.slice(dst_point_range).fill(float3(0));
1999 }
2000 else {
2002 curves_info.handle_left, task.transform, all_handle_left.slice(dst_point_range));
2003 }
2004 if (curves_info.handle_right.is_empty()) {
2005 all_handle_right.slice(dst_point_range).fill(float3(0));
2006 }
2007 else {
2009 curves_info.handle_right, task.transform, all_handle_right.slice(dst_point_range));
2010 }
2011 }
2012
2013 if (all_curves_info.create_radius_attribute) {
2014 if (curves_info.radius.is_empty()) {
2015 all_radii.slice(dst_point_range).fill(1.0f);
2016 }
2017 else {
2018 all_radii.slice(dst_point_range).copy_from(curves_info.radius);
2019 }
2020 }
2021
2022 if (all_curves_info.create_custom_normal_attribute) {
2023 if (curves_info.custom_normal.is_empty()) {
2024 all_custom_normals.slice(dst_point_range).fill(float3(0, 0, 1));
2025 }
2026 else {
2028 float3x3(task.transform),
2029 all_custom_normals.slice(dst_point_range));
2030 }
2031 }
2032
2033 /* Copy curve offsets. */
2034 const Span<int> src_offsets = curves.offsets();
2035 const MutableSpan<int> dst_offsets = dst_curves.offsets_for_write().slice(dst_curve_range);
2036 threading::parallel_for(curves.curves_range(), 2048, [&](const IndexRange range) {
2037 for (const int i : range) {
2038 dst_offsets[i] = task.start_indices.point + src_offsets[i];
2039 }
2040 });
2041
2042 dst_curves.nurbs_custom_knots_for_write()
2043 .slice(dst_custom_knot_range)
2044 .copy_from(curves.nurbs_custom_knots());
2045
2046 if (!all_dst_ids.is_empty()) {
2047 create_result_ids(
2048 options, curves_info.stored_ids, task.id, all_dst_ids.slice(dst_point_range));
2049 }
2050
2051 copy_generic_attributes_to_result(
2052 curves_info.attributes,
2053 task.attribute_fallbacks,
2054 ordered_attributes,
2055 [&](const bke::AttrDomain domain) {
2056 switch (domain) {
2057 case bke::AttrDomain::Point:
2058 return IndexRange(task.start_indices.point, curves.points_num());
2059 case bke::AttrDomain::Curve:
2060 return IndexRange(task.start_indices.curve, curves.curves_num());
2061 default:
2062 BLI_assert_unreachable();
2063 return IndexRange();
2064 }
2065 },
2066 dst_attribute_writers);
2067}
2068
2070 const OrderedAttributes &ordered_attributes,
2071 const Span<const Curves *> src_curves)
2072{
2073 Set<StringRef> existing_names;
2074 LISTBASE_FOREACH (const bDeformGroup *, defgroup, &dst_curve.vertex_group_names) {
2075 existing_names.add(defgroup->name);
2076 }
2077 for (const Curves *src_curve : src_curves) {
2078 LISTBASE_FOREACH (const bDeformGroup *, src, &src_curve->geometry.vertex_group_names) {
2079 if (existing_names.contains(src->name)) {
2080 continue;
2081 }
2082 copy_vertex_group_name(&dst_curve.vertex_group_names, ordered_attributes, *src);
2083 existing_names.add(src->name);
2084 }
2085 }
2086}
2087
2089 const AllCurvesInfo &all_curves_info,
2090 const Span<RealizeCurveTask> tasks,
2091 const OrderedAttributes &ordered_attributes,
2092 bke::GeometrySet &r_realized_geometry)
2093{
2094 if (tasks.is_empty()) {
2095 return;
2096 }
2097
2098 if (tasks.size() == 1) {
2099 const RealizeCurveTask &task = tasks.first();
2100 Curves *new_curves = BKE_curves_copy_for_eval(task.curve_info->curves);
2101 if (!skip_transform(task.transform)) {
2102 new_curves->geometry.wrap().transform(task.transform);
2103 }
2106 new_curves->geometry.wrap().attributes_for_write());
2107 r_realized_geometry.replace_curves(new_curves);
2108 return;
2109 }
2110
2111 const RealizeCurveTask &last_task = tasks.last();
2112 const Curves &last_curves = *last_task.curve_info->curves;
2113 const int points_num = last_task.start_indices.point + last_curves.geometry.point_num;
2114 const int curves_num = last_task.start_indices.curve + last_curves.geometry.curve_num;
2115 const int custom_knot_num = last_task.start_indices.custom_knot +
2116 last_curves.geometry.custom_knot_num;
2117
2118 /* Allocate new curves data-block. */
2119 Curves *dst_curves_id = bke::curves_new_nomain(points_num, curves_num);
2120 bke::CurvesGeometry &dst_curves = dst_curves_id->geometry.wrap();
2121 if (custom_knot_num) {
2122 dst_curves.nurbs_custom_knots_resize(custom_knot_num);
2123 }
2124 dst_curves.offsets_for_write().last() = points_num;
2125 r_realized_geometry.replace_curves(dst_curves_id);
2126 bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
2127
2128 /* Copy settings from the first input geometry set with curves. */
2129 const RealizeCurveTask &first_task = tasks.first();
2130 const Curves &first_curves_id = *first_task.curve_info->curves;
2131 bke::curves_copy_parameters(first_curves_id, *dst_curves_id);
2132
2133 copy_vertex_group_names(dst_curves, ordered_attributes, all_curves_info.order);
2134
2135 /* Prepare id attribute. */
2136 SpanAttributeWriter<int> point_ids;
2137 if (all_curves_info.create_id_attribute) {
2138 point_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id",
2140 }
2141
2142 /* Prepare generic output attributes. */
2143 Vector<GSpanAttributeWriter> dst_attribute_writers;
2144 for (const int attribute_index : ordered_attributes.index_range()) {
2145 const StringRef attribute_id = ordered_attributes.ids[attribute_index];
2146 const bke::AttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
2147 const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
2148 dst_attribute_writers.append(
2149 dst_attributes.lookup_or_add_for_write_only_span(attribute_id, domain, data_type));
2150 }
2151
2152 /* Prepare handle position attributes if necessary. */
2153 SpanAttributeWriter<float3> handle_left;
2154 SpanAttributeWriter<float3> handle_right;
2155 if (all_curves_info.create_handle_postion_attributes) {
2156 handle_left = dst_attributes.lookup_or_add_for_write_only_span<float3>("handle_left",
2158 handle_right = dst_attributes.lookup_or_add_for_write_only_span<float3>(
2159 "handle_right", bke::AttrDomain::Point);
2160 }
2161
2163 if (all_curves_info.create_radius_attribute) {
2164 radius = dst_attributes.lookup_or_add_for_write_only_span<float>("radius",
2166 }
2167 SpanAttributeWriter<float3> custom_normal;
2168 if (all_curves_info.create_custom_normal_attribute) {
2169 custom_normal = dst_attributes.lookup_or_add_for_write_only_span<float3>(
2170 "custom_normal", bke::AttrDomain::Point);
2171 }
2172
2173 /* Actually execute all tasks. */
2174 threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
2175 for (const int task_index : task_range) {
2176 const RealizeCurveTask &task = tasks[task_index];
2177 execute_realize_curve_task(options,
2178 all_curves_info,
2179 task,
2180 ordered_attributes,
2181 dst_curves,
2182 dst_attribute_writers,
2183 point_ids.span,
2184 handle_left.span,
2185 handle_right.span,
2186 radius.span,
2187 custom_normal.span);
2188 }
2189 });
2190
2191 /* Type counts have to be updated eagerly. */
2192 dst_curves.runtime->type_counts.fill(0);
2193 for (const RealizeCurveTask &task : tasks) {
2194 for (const int i : IndexRange(CURVE_TYPES_NUM)) {
2195 dst_curves.runtime->type_counts[i] +=
2196 task.curve_info->curves->geometry.runtime->type_counts[i];
2197 }
2198 }
2199
2200 /* Tag modified attributes. */
2201 for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
2202 dst_attribute.finish();
2203 }
2204 point_ids.finish();
2205 radius.finish();
2206 handle_left.finish();
2207 handle_right.finish();
2208 custom_normal.finish();
2209}
2210
2212
2213/* -------------------------------------------------------------------- */
2216
2218 const bke::GeometrySet &in_geometry_set,
2220 const VariedDepthOptions &varied_depth_options)
2221{
2223 in_geometry_set, bke::GeometryComponent::Type::GreasePencil, options, varied_depth_options);
2224 OrderedAttributes ordered_attributes;
2225 for (auto &&item : attributes_to_propagate.items()) {
2226 ordered_attributes.ids.add_new(item.key);
2227 ordered_attributes.kinds.append(item.value);
2228 }
2229 return ordered_attributes;
2230}
2231
2233 VectorSet<const GreasePencil *> &r_grease_pencils)
2234{
2235 if (const GreasePencil *grease_pencil = geometry_set.get_grease_pencil()) {
2236 if (!grease_pencil->layers().is_empty()) {
2237 r_grease_pencils.add(grease_pencil);
2238 }
2239 }
2240 if (const Instances *instances = geometry_set.get_instances()) {
2241 instances->foreach_referenced_geometry([&](const bke::GeometrySet &instance_geometry_set) {
2242 gather_grease_pencils_to_realize(instance_geometry_set, r_grease_pencils);
2243 });
2244 }
2245}
2246
2248 const bke::GeometrySet &geometry_set,
2250 const VariedDepthOptions &varied_depth_options)
2251{
2254 geometry_set, options, varied_depth_options);
2255
2256 gather_grease_pencils_to_realize(geometry_set, info.order);
2257 info.realize_info.reinitialize(info.order.size());
2258 for (const int grease_pencil_index : info.realize_info.index_range()) {
2259 GreasePencilRealizeInfo &grease_pencil_info = info.realize_info[grease_pencil_index];
2260 const GreasePencil *grease_pencil = info.order[grease_pencil_index];
2261 grease_pencil_info.grease_pencil = grease_pencil;
2262
2263 bke::AttributeAccessor attributes = grease_pencil->attributes();
2264 grease_pencil_info.attributes.reinitialize(info.attributes.size());
2265 for (const int attribute_index : info.attributes.index_range()) {
2266 const StringRef attribute_id = info.attributes.ids[attribute_index];
2267 const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
2268 const bke::AttrDomain domain = info.attributes.kinds[attribute_index].domain;
2269 if (attributes.contains(attribute_id)) {
2270 GVArray attribute = *attributes.lookup_or_default(attribute_id, domain, data_type);
2271 grease_pencil_info.attributes[attribute_index].emplace(std::move(attribute));
2272 }
2273 }
2274
2275 grease_pencil_info.material_index_map.reinitialize(grease_pencil->material_array_num);
2276 for (const int i : IndexRange(grease_pencil->material_array_num)) {
2277 Material *material = grease_pencil->material_array[i];
2278 grease_pencil_info.material_index_map[i] = info.materials.index_of_or_add(material);
2279 }
2280 }
2281 return info;
2282}
2283
2285 const RealizeGreasePencilTask &task,
2286 const OrderedAttributes &ordered_attributes,
2287 GreasePencil &dst_grease_pencil,
2288 MutableSpan<GSpanAttributeWriter> dst_attribute_writers)
2289{
2290 const GreasePencilRealizeInfo &grease_pencil_info = *task.grease_pencil_info;
2291 const GreasePencil &src_grease_pencil = *grease_pencil_info.grease_pencil;
2292 const Span<const bke::greasepencil::Layer *> src_layers = src_grease_pencil.layers();
2293 const IndexRange dst_layers_slice{task.start_index, src_layers.size()};
2294 const Span<bke::greasepencil::Layer *> dst_layers = dst_grease_pencil.layers_for_write().slice(
2295 dst_layers_slice);
2296
2297 for (const int layer_i : src_layers.index_range()) {
2298 const bke::greasepencil::Layer &src_layer = *src_layers[layer_i];
2299 bke::greasepencil::Layer &dst_layer = *dst_layers[layer_i];
2300 BKE_grease_pencil_copy_layer_parameters(src_layer, dst_layer);
2301
2302 dst_layer.set_name(src_layer.name());
2303 dst_layer.set_local_transform(task.transform * src_layer.local_transform());
2304
2305 const bke::greasepencil::Drawing *src_drawing = src_grease_pencil.get_eval_drawing(src_layer);
2306 if (!src_drawing) {
2307 continue;
2308 }
2309 bke::greasepencil::Drawing &dst_drawing = *dst_grease_pencil.get_eval_drawing(dst_layer);
2310
2311 const bke::CurvesGeometry &src_curves = src_drawing->strokes();
2312 bke::CurvesGeometry &dst_curves = dst_drawing.strokes_for_write();
2313 dst_curves = src_curves;
2314
2315 /* Remap materials. */
2316 bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
2317 bke::SpanAttributeWriter<int> material_indices =
2318 dst_attributes.lookup_or_add_for_write_span<int>("material_index", bke::AttrDomain::Curve);
2319 for (int &material_index : material_indices.span) {
2320 if (material_index >= 0 && material_index < src_grease_pencil.material_array_num) {
2321 material_index = grease_pencil_info.material_index_map[material_index];
2322 }
2323 }
2324 material_indices.finish();
2325 }
2326
2328 grease_pencil_info.attributes,
2330 ordered_attributes,
2331 [&](const bke::AttrDomain domain) {
2332 BLI_assert(domain == bke::AttrDomain::Layer);
2333 UNUSED_VARS_NDEBUG(domain);
2334 return dst_layers_slice;
2335 },
2336 dst_attribute_writers);
2337}
2338
2340 const float4x4 &transform)
2341{
2342 for (bke::greasepencil::Layer *layer : layers) {
2343 layer->set_local_transform(transform * layer->local_transform());
2344 }
2345}
2346
2348 const AllGreasePencilsInfo &all_grease_pencils_info,
2350 const OrderedAttributes &ordered_attributes,
2351 bke::GeometrySet &r_realized_geometry)
2352{
2353 if (tasks.is_empty()) {
2354 return;
2355 }
2356
2357 if (tasks.size() == 1) {
2358 const RealizeGreasePencilTask &task = tasks.first();
2360 if (!skip_transform(task.transform)) {
2361 transform_grease_pencil_layers(new_gp->layers_for_write(), task.transform);
2362 }
2364 ordered_attributes, task.attribute_fallbacks, new_gp->attributes_for_write());
2365 r_realized_geometry.replace_grease_pencil(new_gp);
2366 return;
2367 }
2368
2369 const RealizeGreasePencilTask &last_task = tasks.last();
2370 const int new_layers_num = last_task.start_index +
2371 last_task.grease_pencil_info->grease_pencil->layers().size();
2372
2373 /* Allocate new grease pencil. */
2374 GreasePencil *dst_grease_pencil = BKE_grease_pencil_new_nomain();
2375 BKE_grease_pencil_copy_parameters(*tasks.first().grease_pencil_info->grease_pencil,
2376 *dst_grease_pencil);
2377 r_realized_geometry.replace_grease_pencil(dst_grease_pencil);
2378
2379 /* Allocate all layers. */
2380 dst_grease_pencil->add_layers_with_empty_drawings_for_eval(new_layers_num);
2381
2382 /* Transfer material pointers. The material indices are updated for each task separately. */
2383 if (!all_grease_pencils_info.materials.is_empty()) {
2384 MEM_SAFE_FREE(dst_grease_pencil->material_array);
2385 dst_grease_pencil->material_array_num = all_grease_pencils_info.materials.size();
2386 dst_grease_pencil->material_array = MEM_calloc_arrayN<Material *>(
2387 dst_grease_pencil->material_array_num, __func__);
2388 uninitialized_copy_n(all_grease_pencils_info.materials.data(),
2389 dst_grease_pencil->material_array_num,
2390 dst_grease_pencil->material_array);
2391 }
2392
2393 /* Prepare generic output attributes. */
2394 bke::MutableAttributeAccessor dst_attributes = dst_grease_pencil->attributes_for_write();
2395 Vector<GSpanAttributeWriter> dst_attribute_writers;
2396 for (const int attribute_index : ordered_attributes.index_range()) {
2397 const StringRef attribute_id = ordered_attributes.ids[attribute_index];
2398 const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
2399 dst_attribute_writers.append(dst_attributes.lookup_or_add_for_write_only_span(
2400 attribute_id, bke::AttrDomain::Layer, data_type));
2401 }
2402
2403 /* Actually execute all tasks. */
2404 threading::parallel_for(tasks.index_range(), 100, [&](const IndexRange task_range) {
2405 for (const int task_index : task_range) {
2406 const RealizeGreasePencilTask &task = tasks[task_index];
2407 execute_realize_grease_pencil_task(
2408 task, ordered_attributes, *dst_grease_pencil, dst_attribute_writers);
2409 }
2410 });
2411
2412 /* Tag modified attributes. */
2413 for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
2414 dst_attribute.finish();
2415 }
2416}
2417/* -------------------------------------------------------------------- */
2420
2422 bke::GeometrySet &r_realized_geometry)
2423{
2424 if (tasks.is_empty()) {
2425 return;
2426 }
2427
2428 auto &component = r_realized_geometry.get_component_for_write<bke::GeometryComponentEditData>();
2429 for (const RealizeEditDataTask &task : tasks) {
2430 if (!component.curves_edit_hints_) {
2431 if (task.edit_data->curves_edit_hints_) {
2432 component.curves_edit_hints_ = std::make_unique<bke::CurvesEditHints>(
2433 *task.edit_data->curves_edit_hints_);
2434 }
2435 }
2436 if (const bke::GizmoEditHints *src_gizmo_edit_hints = task.edit_data->gizmo_edit_hints_.get())
2437 {
2438 if (!component.gizmo_edit_hints_) {
2439 component.gizmo_edit_hints_ = std::make_unique<bke::GizmoEditHints>();
2440 }
2441 for (auto item : src_gizmo_edit_hints->gizmo_transforms.items()) {
2442 component.gizmo_edit_hints_->gizmo_transforms.add(item.key, task.transform * item.value);
2443 }
2444 }
2445 }
2446}
2447
2449
2450/* -------------------------------------------------------------------- */
2453
2455{
2456 geometry_set.modify_geometry_sets([&](bke::GeometrySet &sub_geometry) {
2457 if (Instances *instances = sub_geometry.get_instances_for_write()) {
2458 instances->attributes_for_write().remove("id");
2459 }
2460 });
2461}
2462
2466static void propagate_instances_to_keep(const bke::GeometrySet &geometry_set,
2467 const IndexMask &selection,
2468 bke::GeometrySet &new_geometry_set,
2469 const bke::AttributeFilter &attribute_filter)
2470{
2471 const Instances &instances = *geometry_set.get_instances();
2472 IndexMaskMemory inverse_selection_indices;
2473 const IndexMask inverse_selection = selection.complement(IndexRange(instances.instances_num()),
2474 inverse_selection_indices);
2475 /* Check not all instances are being realized. */
2476 if (inverse_selection.is_empty()) {
2477 return;
2478 }
2479
2480 std::unique_ptr<Instances> new_instances = std::make_unique<Instances>(instances);
2481 new_instances->remove(inverse_selection, attribute_filter);
2482
2483 bke::InstancesComponent &new_instances_components =
2485 new_instances_components.replace(new_instances.release(), bke::GeometryOwnershipType::Owned);
2486}
2487
2490{
2491 if (!geometry_set.has_instances()) {
2492 return geometry_set;
2493 }
2494
2495 VariedDepthOptions all_instances;
2497 geometry_set.get_instances()->instances_num());
2498 all_instances.selection = IndexMask(geometry_set.get_instances()->instances_num());
2499 return realize_instances(geometry_set, options, all_instances);
2500}
2501
2504 const VariedDepthOptions &varied_depth_option)
2505{
2506 /* The algorithm works in three steps:
2507 * 1. Preprocess each unique geometry that is instanced (e.g. each `Mesh`).
2508 * 2. Gather "tasks" that need to be executed to realize the instances. Each task corresponds
2509 * to instances of the previously preprocessed geometry.
2510 * 3. Execute all tasks in parallel.
2511 */
2512
2513 if (!geometry_set.has_instances()) {
2514 return geometry_set;
2515 }
2516
2517 bke::GeometrySet not_to_realize_set;
2519 geometry_set, varied_depth_option.selection, not_to_realize_set, options.attribute_filter);
2520
2521 if (options.keep_original_ids) {
2523 }
2524
2525 AllPointCloudsInfo all_pointclouds_info = preprocess_pointclouds(
2526 geometry_set, options, varied_depth_option);
2527 AllMeshesInfo all_meshes_info = preprocess_meshes(geometry_set, options, varied_depth_option);
2528 AllCurvesInfo all_curves_info = preprocess_curves(geometry_set, options, varied_depth_option);
2529 AllGreasePencilsInfo all_grease_pencils_info = preprocess_grease_pencils(
2530 geometry_set, options, varied_depth_option);
2532 geometry_set, options, varied_depth_option);
2533
2534 const bool create_id_attribute = all_pointclouds_info.create_id_attribute ||
2535 all_meshes_info.create_id_attribute ||
2536 all_curves_info.create_id_attribute;
2537 Vector<std::unique_ptr<GArray<>>> temporary_arrays;
2538 GatherTasksInfo gather_info = {all_pointclouds_info,
2539 all_meshes_info,
2540 all_curves_info,
2541 all_grease_pencils_info,
2542 all_instance_attributes,
2543 create_id_attribute,
2544 varied_depth_option.selection,
2545 varied_depth_option.depths,
2546 temporary_arrays};
2547
2548 if (not_to_realize_set.has_instances()) {
2549 gather_info.instances.instances_components_to_merge.append(
2550 not_to_realize_set.get_component_for_write<bke::InstancesComponent>().copy());
2552 gather_info.instances.attribute_fallback.append(gather_info.instances_attriubutes.size());
2553 }
2554
2556 InstanceContext attribute_fallbacks(gather_info);
2557
2558 initialize_curves_builtin_attribute_defaults(all_curves_info, attribute_fallbacks);
2559
2561 gather_info, 0, VariedDepthOptions::MAX_DEPTH, geometry_set, transform, attribute_fallbacks);
2562
2563 bke::GeometrySet new_geometry_set;
2566 all_instance_attributes,
2567 gather_info.instances.attribute_fallback,
2568 new_geometry_set);
2569
2570 const int64_t total_points_num = get_final_points_num(gather_info.r_tasks);
2571 /* This doesn't have to be exact at all, it's just a rough estimate to make decisions about
2572 * multi-threading (overhead). */
2573 const int64_t approximate_used_bytes_num = total_points_num * 32;
2574 threading::memory_bandwidth_bound_task(approximate_used_bytes_num, [&]() {
2576 all_pointclouds_info,
2577 gather_info.r_tasks.pointcloud_tasks,
2578 all_pointclouds_info.attributes,
2579 new_geometry_set);
2581 all_meshes_info,
2582 gather_info.r_tasks.mesh_tasks,
2583 all_meshes_info.attributes,
2584 all_meshes_info.materials,
2585 new_geometry_set);
2587 all_curves_info,
2588 gather_info.r_tasks.curve_tasks,
2589 all_curves_info.attributes,
2590 new_geometry_set);
2591 execute_realize_grease_pencil_tasks(all_grease_pencils_info,
2592 gather_info.r_tasks.grease_pencil_tasks,
2593 all_grease_pencils_info.attributes,
2594 new_geometry_set);
2595 execute_realize_edit_data_tasks(gather_info.r_tasks.edit_data_tasks, new_geometry_set);
2596 });
2597 if (gather_info.r_tasks.first_volume) {
2598 new_geometry_set.add(*gather_info.r_tasks.first_volume);
2599 }
2600
2601 return new_geometry_set;
2602}
2603
2605
2606} // 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
#define ELEM(...)
#define CURVE_TYPES_NUM
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
@ CD_PROP_FLOAT2
@ CD_PROP_INT16_2D
@ CD_PROP_STRING
Object is a sort of wrapper for general info.
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:349
const T & first() const
Definition BLI_array.hh:270
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:398
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 ForSingle(T value, const int64_t size)
static VArray ForSpan(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
Span< T > as_span() const
Definition BLI_array.hh:232
void fill_assign_n(const void *value, void *dst, int64_t n) const
const void * default_value() const
GMutableSpan slice(const int64_t start, int64_t size) const
const CPPType & type() const
const CPPType * type() const
const void * get() const
Span< T > typed() const
const CPPType & type() const
int64_t size() const
static GVArray ForSingle(const CPPType &type, int64_t size, const void *value)
constexpr int64_t size() const
std::optional< Value > pop_try(const Key &key)
Definition BLI_map.hh:419
bool remove(const Key &key)
Definition BLI_map.hh:368
auto add_or_modify(const Key &key, const CreateValueF &create_value, const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
Definition BLI_map.hh:481
ItemIterator items() const &
Definition BLI_map.hh:902
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 const T & last(const int64_t n=0) const
Definition BLI_span.hh:325
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
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
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const void *default_value=nullptr) const
int domain_size(const AttrDomain domain) const
std::optional< AttributeMetaData > lookup_meta_data(StringRef attribute_id) 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:93
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:233
Span< InstanceReference > references() const
Definition instances.cc:285
bke::AttributeAccessor attributes() const
Definition instances.cc:63
int instances_num() const
Definition instances.cc:398
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
bool add(const StringRef attribute_id, const AttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer)
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type)
bke::CurvesGeometry & strokes_for_write()
const bke::CurvesGeometry & strokes() const
void set_local_transform(const float4x4 &transform)
IndexMask complement(const IndexMask &universe, IndexMaskMemory &memory) const
void foreach_index(Fn &&fn) const
CCL_NAMESPACE_BEGIN struct Options options
static ushort indices[]
VecBase< short, 2 > short2
MatBase< 4, 4 > float4x4
VecBase< float, 3 > float3
MatBase< 3, 3 > float3x3
#define MEM_SAFE_FREE(v)
static void transform_positions(const Span< blender::float3 > src, const blender::float4x4 &transform, blender::MutableSpan< blender::float3 > dst)
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
static void add(blender::Map< std::string, std::string > &messages, Message &msg)
Definition msgfmt.cc:222
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)
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)
eCustomDataType attribute_data_type_highest_complexity(Span< eCustomDataType > data_types)
AttrDomain attribute_domain_highest_priority(Span< AttrDomain > domains)
const CPPType * custom_data_type_to_cpp_type(eCustomDataType 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 execute_realize_mesh_tasks(const RealizeInstancesOptions &options, const AllMeshesInfo &all_meshes_info, const Span< RealizeMeshTask > tasks, const OrderedAttributes &ordered_attributes, const VectorSet< Material * > &ordered_materials, bke::GeometrySet &r_realized_geometry)
static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info, const int current_depth, const int target_depth, const bke::GeometrySet &geometry_set, const float4x4 &base_transform, const InstanceContext &base_instance_context)
static OrderedAttributes gather_generic_pointcloud_attributes_to_propagate(const bke::GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, const VariedDepthOptions &varied_depth_option, bool &r_create_radii, bool &r_create_id)
static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &options, const AllPointCloudsInfo &all_pointclouds_info, const Span< RealizePointCloudTask > tasks, const OrderedAttributes &ordered_attributes, bke::GeometrySet &r_realized_geometry)
static void copy_vertex_group_name(ListBase *dst_deform_group, const OrderedAttributes &ordered_attributes, const bDeformGroup &src_deform_group)
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_curve_tasks(const RealizeInstancesOptions &options, const AllCurvesInfo &all_curves_info, const Span< RealizeCurveTask > tasks, const OrderedAttributes &ordered_attributes, bke::GeometrySet &r_realized_geometry)
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 Map< StringRef, AttributeDomainAndType > gather_attributes_to_propagate(const bke::GeometrySet &geometry, const bke::GeometryComponent::Type component_type, const RealizeInstancesOptions &options, const VariedDepthOptions &varied_depth_option)
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)
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 void copy_vertex_group_names(Mesh &dst_mesh, const OrderedAttributes &ordered_attributes, const Span< const Mesh * > src_meshes)
static bke::AttrDomain normal_domain_to_domain(bke::MeshNormalDomain domain)
static AllCurvesInfo preprocess_curves(const bke::GeometrySet &geometry_set, const RealizeInstancesOptions &options, const VariedDepthOptions &varied_depth_option)
static void gather_meshes_to_realize(const bke::GeometrySet &geometry_set, VectorSet< const Mesh * > &r_meshes)
static void add_instance_attributes_to_single_geometry(const OrderedAttributes &ordered_attributes, const AttributeFallbacksArray &attribute_fallbacks, bke::MutableAttributeAccessor attributes)
static AllGreasePencilsInfo preprocess_grease_pencils(const bke::GeometrySet &geometry_set, const RealizeInstancesOptions &options, const VariedDepthOptions &varied_depth_options)
static OrderedAttributes gather_generic_instance_attributes_to_propagate(const bke::GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, const VariedDepthOptions &varied_depth_option)
static void foreach_geometry_in_reference(const InstanceReference &reference, const float4x4 &base_transform, const uint32_t id, FunctionRef< void(const bke::GeometrySet &geometry_set, const float4x4 &transform, uint32_t id)> fn)
static void threaded_fill(const GPointer value, GMutableSpan dst)
static void execute_realize_edit_data_tasks(const Span< RealizeEditDataTask > tasks, bke::GeometrySet &r_realized_geometry)
static bool skip_transform(const float4x4 &transform)
static OrderedAttributes gather_generic_grease_pencil_attributes_to_propagate(const bke::GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, const VariedDepthOptions &varied_depth_options)
bke::GeometrySet realize_instances(bke::GeometrySet geometry_set, const RealizeInstancesOptions &options)
constexpr bke::AttributeMetaData CORNER_FAN_META_DATA
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 void execute_realize_grease_pencil_tasks(const AllGreasePencilsInfo &all_grease_pencils_info, const Span< RealizeGreasePencilTask > tasks, const OrderedAttributes &ordered_attributes, bke::GeometrySet &r_realized_geometry)
static void copy_transformed_positions(const Span< float3 > src, const float4x4 &transform, MutableSpan< float3 > dst)
static OrderedAttributes gather_generic_mesh_attributes_to_propagate(const bke::GeometrySet &in_geometry_set, const RealizeInstancesOptions &options, const VariedDepthOptions &varied_depth_option, bool &r_create_id, bool &r_create_material_index)
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))
uint32_t hash(uint32_t kx)
Definition noise.cc:77
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
GeometryComponent & get_component_for_write(GeometryComponent::Type component_type)
void replace_instances(Instances *instances, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
Instances * get_instances_for_write()
const GreasePencil * get_grease_pencil() const
Vector< const GeometryComponent * > get_components() const
void replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
const Curves * get_curves() const
const Instances * get_instances() const
void replace_curves(Curves *curves, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
const PointCloud * get_pointcloud() const
const Mesh * get_mesh() const
void modify_geometry_sets(ForeachSubGeometryCallback callback)
void replace_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
void add(const GeometryComponent &component)
void replace_grease_pencil(GreasePencil *grease_pencil, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
VectorSet< const Curves * > order
Array< RealizeCurveInfo > realize_info
VectorSet< const GreasePencil * > order
Array< GreasePencilRealizeInfo > realize_info
Vector< AttributeFallbacksArray > attribute_fallback
Vector< bke::GeometryComponentPtr > instances_components_to_merge
VectorSet< const Mesh * > order
Array< MeshRealizeInfo > realize_info
Array< PointCloudRealizeInfo > realize_info
VectorSet< const PointCloud * > order
MeshElementStartIndices mesh_offsets
CurvesElementStartIndices curves_offsets
const AllPointCloudsInfo & pointclouds
Vector< std::unique_ptr< GArray<> > > & r_temporary_arrays
const OrderedAttributes & instances_attriubutes
const AllGreasePencilsInfo & grease_pencils
Vector< RealizeMeshTask > mesh_tasks
Vector< RealizeEditDataTask > edit_data_tasks
Vector< RealizePointCloudTask > pointcloud_tasks
Vector< RealizeCurveTask > curve_tasks
ImplicitSharingPtr< const bke::VolumeComponent > first_volume
Vector< RealizeGreasePencilTask > grease_pencil_tasks
Array< std::optional< GVArraySpan > > attributes
InstanceContext(const GatherTasksInfo &gather_info)
std::optional< bke::AttrDomain > result_domain
void add_domain(const bke::AttrDomain domain)
void add_free_normals(const bke::AttrDomain domain)
void add_no_custom_normals(const bke::MeshNormalDomain domain)
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