133 const int max_neighbor_count,
139 for (const int child_curve_i : range) {
140 const float3 &position = positions[child_curve_i];
141 const int group = point_group_ids[child_curve_i];
142 const KDTree_3d *kdtree = kdtrees.lookup_default(group, nullptr);
143 if (kdtree == nullptr) {
144 r_all_neighbor_counts[child_curve_i] = 0;
148 const int num_guides_in_group = guides_by_group.lookup(group).size();
152 const bool use_extra_neighbor = num_guides_in_group > max_neighbor_count;
153 const int neighbors_to_find = max_neighbor_count + use_extra_neighbor;
155 Vector<KDTreeNearest_3d, 16> nearest_n(neighbors_to_find);
156 const int num_neighbors = BLI_kdtree_3d_find_nearest_n(
157 kdtree, position, nearest_n.data(), neighbors_to_find);
158 if (num_neighbors == 0) {
159 r_all_neighbor_counts[child_curve_i] = 0;
163 const IndexRange neighbors_range{child_curve_i * max_neighbor_count, max_neighbor_count};
164 MutableSpan<int> neighbor_indices = r_all_neighbor_indices.slice(neighbors_range);
165 MutableSpan<float> neighbor_weights = r_all_neighbor_weights.slice(neighbors_range);
167 float tot_weight = 0.0f;
169 if (use_extra_neighbor) {
172 const float max_distance = std::max_element(
174 nearest_n.begin() + num_neighbors,
175 [](const KDTreeNearest_3d &a, const KDTreeNearest_3d &b) {
176 return a.dist < b.dist;
179 if (max_distance == 0.0f) {
180 r_all_neighbor_counts[child_curve_i] = 1;
181 neighbor_indices[0] = nearest_n[0].index;
182 neighbor_weights[0] = 1.0f;
186 int neighbor_counter = 0;
187 for (const int neighbor_i : IndexRange(num_neighbors)) {
188 const KDTreeNearest_3d &nearest = nearest_n[neighbor_i];
192 const float weight = (max_distance - nearest.dist) / std::max(nearest.dist, 0.000001f);
194 tot_weight += weight;
195 neighbor_indices[neighbor_counter] = nearest.index;
196 neighbor_weights[neighbor_counter] = weight;
200 r_all_neighbor_counts[child_curve_i] = neighbor_counter;
203 int neighbor_counter = 0;
204 for (const int neighbor_i : IndexRange(num_neighbors)) {
205 const KDTreeNearest_3d &nearest = nearest_n[neighbor_i];
209 const float weight = 1.0f / std::max(nearest.dist, 0.000001f);
211 tot_weight += weight;
212 neighbor_indices[neighbor_counter] = nearest.index;
213 neighbor_weights[neighbor_counter] = weight;
217 r_all_neighbor_counts[child_curve_i] = neighbor_counter;
219 if (tot_weight > 0.0f) {
221 const float weight_factor = 1.0f / tot_weight;
222 for (float &weight : neighbor_weights.take_front(r_all_neighbor_counts[child_curve_i])) {
223 weight *= weight_factor;
240 const int max_neighbors,
246 for (const int child_curve_i : range) {
247 const int neighbor_count = all_neighbor_counts[child_curve_i];
248 if (neighbor_count == 0) {
249 r_points_per_child[child_curve_i] = 1;
250 r_use_direct_interpolation[child_curve_i] = false;
253 const int group = point_group_ids[child_curve_i];
254 const int points_per_curve_in_group = points_per_curve_by_group.lookup_default(group, -1);
255 if (points_per_curve_in_group != -1) {
256 r_points_per_child[child_curve_i] = points_per_curve_in_group;
257 r_use_direct_interpolation[child_curve_i] = true;
260 const IndexRange neighbors_range{child_curve_i * max_neighbors, neighbor_count};
261 const Span<float> neighbor_weights = all_neighbor_weights.slice(neighbors_range);
262 const Span<int> neighbor_indices = all_neighbor_indices.slice(neighbors_range);
264 float neighbor_points_weighted_sum = 0.0f;
265 for (const int neighbor_i : IndexRange(neighbor_count)) {
266 const int neighbor_index = neighbor_indices[neighbor_i];
267 const float neighbor_weight = neighbor_weights[neighbor_i];
268 const int neighbor_points = guide_points_by_curve[neighbor_index].size();
269 neighbor_points_weighted_sum += neighbor_weight * float(neighbor_points);
271 const int points_in_child = std::max<int>(1, roundf(neighbor_points_weighted_sum));
272 r_points_per_child[child_curve_i] = points_in_child;
273 r_use_direct_interpolation[child_curve_i] = false;
288 for (const int guide_curve_i : range) {
289 r_parameterized_guide_offsets[guide_curve_i] = length_parameterize::segments_num(
290 guide_points_by_curve[guide_curve_i].size(), false);
293 offset_indices::accumulate_counts_to_offsets(r_parameterized_guide_offsets);
296 r_parameterized_guide_lengths.reinitialize(r_parameterized_guide_offsets.last());
297 const Span<float3> guide_positions = guide_curves.positions();
298 threading::parallel_for(guide_curves.curves_range(), 256, [&](
const IndexRange range) {
299 for (const int guide_curve_i : range) {
300 const IndexRange points = guide_points_by_curve[guide_curve_i];
301 const IndexRange lengths_range = parameterize_offsets[guide_curve_i];
302 length_parameterize::accumulate_lengths<float3>(
303 guide_positions.slice(points),
305 r_parameterized_guide_lengths.as_mutable_span().slice(lengths_range));
315 const int max_neighbors,
324 const Span<bool> use_direct_interpolation_per_child)
332 Vector<float, 16> sample_lengths;
333 Vector<int, 16> sample_segments;
334 Vector<float, 16> sample_factors;
336 for (const int child_curve_i : range) {
337 const IndexRange points = child_points_by_curve[child_curve_i];
338 const int neighbor_count = all_neighbor_counts[child_curve_i];
339 const float3 child_up = points_up[child_curve_i];
340 BLI_assert(math::is_unit_scale(child_up));
341 const float3 &child_root_position = point_positions[child_curve_i];
342 MutableSpan<float3> child_positions = children_positions.slice(points);
344 child_positions.fill(child_root_position);
345 if (neighbor_count == 0) {
350 const IndexRange neighbors_range{child_curve_i * max_neighbors, neighbor_count};
351 const Span<float> neighbor_weights = all_neighbor_weights.slice(neighbors_range);
352 const Span<int> neighbor_indices = all_neighbor_indices.slice(neighbors_range);
354 const bool use_direct_interpolation = use_direct_interpolation_per_child[child_curve_i];
356 for (const int neighbor_i : IndexRange(neighbor_count)) {
357 const int neighbor_index = neighbor_indices[neighbor_i];
358 const float neighbor_weight = neighbor_weights[neighbor_i];
359 const IndexRange guide_points = guide_points_by_curve[neighbor_index];
360 const Span<float3> neighbor_positions = guide_positions.slice(guide_points);
361 const float3 &neighbor_root = neighbor_positions.first();
362 const float3 neighbor_up = guides_up[neighbor_index];
363 BLI_assert(math::is_unit_scale(neighbor_up));
365 const bool is_same_up_vector = neighbor_up == child_up;
367 float3x3 normal_rotation;
368 if (!is_same_up_vector) {
369 rotation_between_vecs_to_mat3(normal_rotation.ptr(), neighbor_up, child_up);
372 if (use_direct_interpolation) {
376 for (const int i : IndexRange(points.size())) {
377 const float3 &neighbor_pos = neighbor_positions[i];
378 const float3 relative_to_root = neighbor_pos - neighbor_root;
379 float3 rotated_relative = relative_to_root;
380 if (!is_same_up_vector) {
381 rotated_relative = normal_rotation * rotated_relative;
383 child_positions[i] += neighbor_weight * rotated_relative;
390 const IndexRange guide_offsets = parameterized_guide_offsets[neighbor_index];
392 if (guide_offsets.is_empty()) {
394 float3 rotated_relative = neighbor_root;
395 if (!is_same_up_vector) {
396 rotated_relative = normal_rotation * rotated_relative;
398 const float3 global_pos = rotated_relative * neighbor_weight;
399 for (float3 &position : child_positions) {
400 position += global_pos;
405 const Span<float> lengths = parameterized_guide_lengths.slice(guide_offsets);
406 const float neighbor_length = lengths.last();
408 sample_lengths.reinitialize(points.size());
409 const float sample_length_factor = math::safe_divide(neighbor_length,
410 float(points.size() - 1));
411 for (const int i : sample_lengths.index_range()) {
412 sample_lengths[i] = i * sample_length_factor;
415 sample_segments.reinitialize(points.size());
416 sample_factors.reinitialize(points.size());
417 length_parameterize::sample_at_lengths(
418 lengths, sample_lengths, sample_segments, sample_factors);
420 for (const int i : IndexRange(points.size())) {
421 const int segment = sample_segments[i];
422 const float factor = sample_factors[i];
423 const float3 sample_pos = math::interpolate(
424 neighbor_positions[segment], neighbor_positions[segment + 1], factor);
425 const float3 relative_to_root = sample_pos - neighbor_root;
426 float3 rotated_relative = relative_to_root;
427 if (!is_same_up_vector) {
428 rotated_relative = normal_rotation * rotated_relative;
430 child_positions[i] += neighbor_weight * rotated_relative;
448 const int max_neighbors,
454 const Span<bool> use_direct_interpolation_per_child)
476 if (iter.
domain == AttrDomain::Curve) {
477 const GVArraySpan src_generic = *iter.
get(AttrDomain::Curve, type);
480 iter.
name, AttrDomain::Curve, type);
484 bke::attribute_math::convert_to_static_type(type, [&](
auto dummy) {
485 using T =
decltype(dummy);
491 for (const int child_curve_i : range) {
492 const int neighbor_count = all_neighbor_counts[child_curve_i];
493 const IndexRange neighbors_range{child_curve_i * max_neighbors, neighbor_count};
494 const Span<float> neighbor_weights = all_neighbor_weights.slice(neighbors_range);
495 const Span<int> neighbor_indices = all_neighbor_indices.slice(neighbors_range);
497 for (const int neighbor_i : IndexRange(neighbor_count)) {
498 const int neighbor_index = neighbor_indices[neighbor_i];
499 const float neighbor_weight = neighbor_weights[neighbor_i];
500 mixer.mix_in(child_curve_i, src[neighbor_index], neighbor_weight);
503 mixer.finalize(range);
511 const GVArraySpan src_generic = *iter.
get(AttrDomain::Point, type);
513 iter.
name, AttrDomain::Point, type);
518 bke::attribute_math::convert_to_static_type(type, [&](
auto dummy) {
519 using T =
decltype(dummy);
525 Vector<float, 16> sample_lengths;
526 Vector<int, 16> sample_segments;
527 Vector<float, 16> sample_factors;
528 for (const int child_curve_i : range) {
529 const IndexRange points = child_points_by_curve[child_curve_i];
530 const int neighbor_count = all_neighbor_counts[child_curve_i];
531 const IndexRange neighbors_range{child_curve_i * max_neighbors, neighbor_count};
532 const Span<float> neighbor_weights = all_neighbor_weights.slice(neighbors_range);
533 const Span<int> neighbor_indices = all_neighbor_indices.slice(neighbors_range);
534 const bool use_direct_interpolation =
535 use_direct_interpolation_per_child[child_curve_i];
537 for (const int neighbor_i : IndexRange(neighbor_count)) {
538 const int neighbor_index = neighbor_indices[neighbor_i];
539 const float neighbor_weight = neighbor_weights[neighbor_i];
540 const IndexRange guide_points = guide_points_by_curve[neighbor_index];
542 if (use_direct_interpolation) {
543 for (const int i : IndexRange(points.size())) {
544 mixer.mix_in(points[i], src[guide_points[i]], neighbor_weight);
548 const IndexRange guide_offsets = parameterized_guide_offsets[neighbor_index];
549 if (guide_offsets.is_empty()) {
551 const T &curve_value = src[guide_points.first()];
552 for (const int i : points) {
553 mixer.mix_in(i, curve_value, neighbor_weight);
558 const Span<float> lengths = parameterized_guide_lengths.slice(guide_offsets);
559 const float neighbor_length = lengths.last();
561 sample_lengths.reinitialize(points.size());
562 const float sample_length_factor = math::safe_divide(neighbor_length,
563 float(points.size() - 1));
564 for (const int i : sample_lengths.index_range()) {
565 sample_lengths[i] = i * sample_length_factor;
568 sample_segments.reinitialize(points.size());
569 sample_factors.reinitialize(points.size());
570 length_parameterize::sample_at_lengths(
571 lengths, sample_lengths, sample_segments, sample_factors);
573 for (const int i : IndexRange(points.size())) {
574 const int segment = sample_segments[i];
575 const float factor = sample_factors[i];
576 const T value = math::interpolate(
577 src[guide_points[segment]], src[guide_points[segment + 1]], factor);
578 mixer.mix_in(points[i], value, neighbor_weight);
583 mixer.finalize(child_points_by_curve[range]);
594 if (iter.
is_builtin && !children_attributes.is_builtin(iter.
name)) {
597 if (guide_curve_attributes.contains(iter.
name)) {
600 if (attribute_filter.allow_skip(iter.
name)) {
607 const GAttributeReader src = iter.
get();
608 if (src.sharing_info && src.varray.is_span()) {
609 const bke::AttributeInitShared
init(src.varray.get_internal_span().data(),
614 children_attributes.add(
615 iter.
name, AttrDomain::Curve, iter.
data_type, bke::AttributeInitVArray(src.varray));
621 const std::optional<StringRef> &weight_attribute_id,
622 const std::optional<StringRef> &index_attribute_id,
623 const int max_neighbors,
628 if (!weight_attribute_id && !index_attribute_id) {
632 if (weight_attribute_id) {
635 *weight_attribute_id, AttrDomain::Curve);
638 if (index_attribute_id) {
640 *index_attribute_id, AttrDomain::Curve);
643 for (const int child_curve_i : range) {
644 const int neighbor_count = all_neighbor_counts[child_curve_i];
647 float closest_weight;
648 if (neighbor_count == 0) {
650 closest_weight = 0.0f;
653 const IndexRange neighbors_range{child_curve_i * max_neighbors, neighbor_count};
654 const Span<float> neighbor_weights = all_neighbor_weights.slice(neighbors_range);
655 const Span<int> neighbor_indices = all_neighbor_indices.slice(neighbors_range);
656 const int max_index = std::max_element(neighbor_weights.begin(), neighbor_weights.end()) -
657 neighbor_weights.begin();
658 closest_index = neighbor_indices[max_index];
659 closest_weight = neighbor_weights[max_index];
661 if (index_attribute) {
662 index_attribute.span[child_curve_i] = closest_index;
664 if (weight_attribute) {
665 weight_attribute.span[child_curve_i] = closest_weight;
669 if (index_attribute) {
672 if (weight_attribute) {
673 weight_attribute.finish();
678 const Curves &guide_curves_id,
684 const int max_neighbors,
686 const std::optional<StringRef> &index_attribute_id,
687 const std::optional<StringRef> &weight_attribute_id)
693 guides_by_group, guide_curves);
697 for (KDTree_3d *kdtree : kdtrees.
values()) {
698 BLI_kdtree_3d_free(kdtree);
703 const int num_child_curves = point_attributes.
domain_size(AttrDomain::Point);
707 Array<int> all_neighbor_indices(num_child_curves * max_neighbors);
708 Array<float> all_neighbor_weights(num_child_curves * max_neighbors);
709 Array<int> all_neighbor_counts(num_child_curves);
716 all_neighbor_indices,
717 all_neighbor_weights,
718 all_neighbor_counts);
720 Curves *child_curves_id = bke::curves_new_nomain(0, num_child_curves);
724 Array<bool> use_direct_interpolation_per_child(num_child_curves);
727 points_per_curve_by_group,
728 all_neighbor_indices,
729 all_neighbor_weights,
733 use_direct_interpolation_per_child);
734 offset_indices::accumulate_counts_to_offsets(children_curve_offsets);
735 const int num_child_points = children_curve_offsets.
last();
736 child_curves.
resize(num_child_points, num_child_curves);
742 guide_curves, parameterized_guide_offsets, parameterized_guide_lengths);
747 all_neighbor_indices,
748 all_neighbor_weights,
754 parameterized_guide_lengths,
755 use_direct_interpolation_per_child);
761 all_neighbor_indices,
762 all_neighbor_weights,
765 parameterized_guide_lengths,
766 use_direct_interpolation_per_child);
773 all_neighbor_indices,
774 all_neighbor_weights);
776 if (guide_curves_id.
mat !=
nullptr) {
781 geometry::debug_randomize_curve_order(&child_curves);
783 return GeometrySet::from_curves(child_curves_id);
794 params.set_default_remaining_outputs();
798 if (points_component ==
nullptr) {
799 points_component = points_geometry.get_component<
MeshComponent>();
801 if (points_component ==
nullptr || points_geometry.
is_empty()) {
802 params.set_default_remaining_outputs();
806 const int max_neighbors = std::max<int>(1,
params.extract_input<
int>(
"Max Neighbors"));
808 static auto normalize_fn = mf::build::SI1_SO<float3, float3>(
811 mf::build::exec_presets::AllSpanOrSingle());
825 fn::FieldEvaluator curves_evaluator{curves_context, guide_curves_id.geometry.curve_num};
826 curves_evaluator.add(guides_up_field);
827 curves_evaluator.add(guide_group_field);
828 curves_evaluator.evaluate();
830 const VArray<int> guide_group_ids = curves_evaluator.get_evaluated<
int>(1);
835 points_evaluator.add(points_up_field);
836 points_evaluator.add(point_group_field);
837 points_evaluator.evaluate();
839 const VArray<int> point_group_ids = points_evaluator.get_evaluated<
int>(1);
843 std::optional<std::string> index_attribute_id =
844 params.get_output_anonymous_attribute_id_if_needed(
"Closest Index");
845 std::optional<std::string> weight_attribute_id =
846 params.get_output_anonymous_attribute_id_if_needed(
"Closest Weight");
857 weight_attribute_id);
859 GeometryComponentEditData::remember_deformed_positions_if_necessary(guide_curves_geometry);
860 if (
const auto *curve_edit_data =
863 new_curves.
add(*curve_edit_data);
865 new_curves.
name = guide_curves_geometry.
name;
867 params.set_output(
"Curves", std::move(new_curves));