29using bke::CurvesGeometry;
46 bary_coord, corner_tri, corner_normals);
61 const KDTree_3d &old_roots_kdtree)
63 const int tot_added_curves = root_positions.
size();
66 for (
const int i : range) {
67 const float3 root = root_positions[i];
68 std::array<KDTreeNearest_3d, max_neighbors> nearest_n;
69 const int found_neighbors = BLI_kdtree_3d_find_nearest_n(
71 float tot_weight = 0.0f;
72 for (
const int neighbor_i :
IndexRange(found_neighbors)) {
73 KDTreeNearest_3d &nearest = nearest_n[neighbor_i];
74 const float weight = 1.0f / std::max(nearest.dist, 0.00001f);
76 neighbors_per_curve[i].append({nearest.index, weight});
80 neighbor.weight /= tot_weight;
84 return neighbors_per_curve;
87template<
typename T,
typename GetValueF>
90 const GetValueF &get_value_from_neighbor,
95 for (const int i : range) {
96 const NeighborCurves &neighbors = neighbors_per_curve[i];
97 if (neighbors.is_empty()) {
98 mixer.mix_in(i, fallback, 1.0f);
101 for (const NeighborCurve &neighbor : neighbors) {
102 const T neighbor_value = get_value_from_neighbor(neighbor.index);
103 mixer.mix_in(i, neighbor_value, neighbor.weight);
107 mixer.finalize(range);
112 const int old_curves_num,
116 const float4x4 &surface_to_curves_normal_mat)
118 const int added_curves_num = root_positions_cu.
size();
122 for (
const int i : range) {
123 const int curve_i = old_curves_num + i;
124 const IndexRange points = points_by_curve[curve_i];
125 const float3 &root_cu = root_positions_cu[i];
126 const float length = new_lengths_cu[i];
127 const float3 &normal_su = new_normals_su[i];
140 const int old_curves_num,
149 const int added_curves_num = root_positions_cu.
size();
155 for (
const int added_curve_i : range) {
156 const NeighborCurves &neighbors = neighbors_per_curve[added_curve_i];
157 const int curve_i = old_curves_num + added_curve_i;
158 const IndexRange points = points_by_curve[curve_i];
160 const float length_cu = new_lengths_cu[added_curve_i];
161 const float3 &normal_su = new_normals_su[added_curve_i];
165 const float3 &root_cu = root_positions_cu[added_curve_i];
169 const float3 tip_cu = root_cu + length_cu * normal_cu;
174 positions_cu.
slice(points).
fill(root_cu);
177 const int neighbor_curve_i = neighbor.index;
178 const float2 neighbor_uv = uv_coords[neighbor_curve_i];
185 corner_tris[
result.tri_index],
result.bary_weights, corner_normals_su);
191 float normal_rotation_cu[3][3];
194 const IndexRange neighbor_points = points_by_curve[neighbor_curve_i];
195 const float3 &neighbor_root_cu = positions_cu[neighbor_points[0]];
205 if (neighbor_positions_cu.
size() == 1) {
211 const float neighbor_length_cu = lengths.
last();
214 const float length_factor = std::min(1.0f, length_cu / neighbor_length_cu);
215 const float resample_factor = (1.0f / (points.
size() - 1.0f)) * length_factor;
217 sample_lengths[i] = i * resample_factor * neighbor_length_cu;
226 neighbor_positions_cu[
indices[i] + 1],
228 const float3 relative_to_root_cu = sample_cu - neighbor_root_cu;
229 float3 rotated_relative_coord = relative_to_root_cu;
230 mul_m3_v3(normal_rotation_cu, rotated_relative_coord);
231 positions_cu[points[i]] += neighbor.weight * rotated_relative_coord;
245 radius_attr.
span.slice(new_points_range).fill(radius);
250 const int old_curves_num,
255 const int added_curves_num = new_lengths_cu.
size();
267 for (
const int i : range) {
269 const float length_cu = new_lengths_cu[i];
270 const int curve_i = old_curves_num + i;
271 const IndexRange points = points_by_curve[curve_i];
282 const int neighbor_curve_i = neighbor.index;
283 const IndexRange neighbor_points = points_by_curve[neighbor_curve_i];
285 const Span<float> neighbor_radii_cu = radius_attr.
span.slice(neighbor_points);
290 const float neighbor_length_cu = lengths.
last();
293 const float length_factor = std::min(1.0f, length_cu / neighbor_length_cu);
294 const float resample_factor = (1.0f / (points.
size() - 1.0f)) * length_factor;
296 sample_lengths[i] = i * resample_factor * neighbor_length_cu;
305 neighbor_radii_cu[
indices[i]], neighbor_radii_cu[
indices[i] + 1], factors[i]);
307 radii_cu[points[i]] += neighbor.weight * sample_cu;
320 const bool use_interpolation =
inputs.interpolate_length ||
inputs.interpolate_point_count ||
321 inputs.interpolate_radius ||
inputs.interpolate_shape ||
322 inputs.interpolate_resolution;
332 for (
const int i :
inputs.uvs.index_range()) {
344 surface_positions[surface_corner_verts[tri[0]]],
345 surface_positions[surface_corner_verts[tri[1]]],
346 surface_positions[surface_corner_verts[tri[2]]]);
353 if (use_interpolation) {
358 const int added_curves_num = root_positions_cu.
size();
359 const int old_points_num = curves.
points_num();
360 const int old_curves_num = curves.
curves_num();
361 const int new_curves_num = old_curves_num + added_curves_num;
364 curves.
resize(old_points_num, new_curves_num);
365 if (new_curves_num == 0) {
371 Array<int> new_point_counts_per_curve(added_curves_num);
372 if (
inputs.interpolate_point_count && old_curves_num > 0) {
376 inputs.fallback_point_count,
377 [&](
const int curve_i) { return old_points_by_curve[curve_i].size(); },
378 new_point_counts_per_curve);
381 new_point_counts_per_curve.
fill(
inputs.fallback_point_count);
383 curve_offsets[old_curves_num] = old_points_num;
384 int offset = old_points_num;
385 for (
const int i : new_point_counts_per_curve.
index_range()) {
386 const int point_count_in_curve = new_point_counts_per_curve[i];
387 curve_offsets[old_curves_num + i + 1] = offset + point_count_in_curve;
388 offset += point_count_in_curve;
391 const int new_points_num = curves.
offsets().
last();
392 curves.
resize(new_points_num, new_curves_num);
406 if (
inputs.interpolate_length) {
409 inputs.fallback_curve_length,
410 [&](
const int curve_i) {
411 const IndexRange points = points_by_curve[curve_i];
413 for (const int segment_i : points.drop_back(1)) {
414 const float3 &p1 = positions_cu[segment_i];
415 const float3 &p2 = positions_cu[segment_i + 1];
416 length += math::distance(p1, p2);
423 new_lengths_cu.fill(
inputs.fallback_curve_length);
428 bke::mesh_surface_sample::sample_corner_normals(
inputs.surface_corner_tris,
436 if (
inputs.interpolate_shape) {
437 calc_position_with_interpolation(curves,
444 inputs.surface_corner_tris,
445 *
inputs.reverse_uv_sampler,
446 inputs.corner_normals_su);
454 inputs.transforms->surface_to_curves_normal);
458 if (
inputs.interpolate_radius) {
460 curves, old_curves_num,
inputs.fallback_curve_radius, new_lengths_cu, neighbors_per_curve);
464 curves,
outputs.new_points_range,
inputs.fallback_curve_radius);
469 bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
471 if (bke::SpanAttributeWriter<int> resolution = attributes.lookup_for_write_span<
int>(
474 if (
inputs.interpolate_resolution) {
478 [&](
const int curve_i) {
return resolution.span[curve_i]; },
479 resolution.span.take_back(added_curves_num));
483 resolution.span.take_back(added_curves_num).fill(12);
488 bke::fill_attribute_range_default(attributes,
489 bke::AttrDomain::Point,
490 bke::attribute_filter_from_skip_ref({
"position",
"radius"}),
492 bke::fill_attribute_range_default(
494 bke::AttrDomain::Curve,
495 bke::attribute_filter_from_skip_ref({
"curve_type",
"surface_uv_coordinate",
"resolution"}),
A KD-tree for nearest neighbor search.
void mul_m3_v3(const float M[3][3], float r[3])
void rotation_between_vecs_to_mat3(float m[3][3], const float v1[3], const float v2[3])
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
constexpr const T & last(const int64_t n=0) const
const T & last(const int64_t n=0) const
IndexRange index_range() const
void fill(const T &value) const
constexpr int64_t size() const
constexpr IndexRange drop_front(int64_t n) const
constexpr int64_t size() const
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
constexpr MutableSpan take_back(const int64_t n) const
constexpr void fill(const T &value) const
constexpr IndexRange index_range() const
constexpr void copy_from(Span< T > values) const
constexpr MutableSpan take_front(const int64_t n) const
constexpr int64_t size() const
void append(const T &value)
MutableSpan< float3 > positions_for_write()
OffsetIndices< int > points_by_curve() const
IndexRange curves_range() const
MutableAttributeAccessor attributes_for_write()
MutableSpan< float2 > surface_uv_coords_for_write()
IndexRange points_range() const
Span< int > offsets() const
Span< float3 > positions() const
void resize(int points_num, int curves_num)
MutableSpan< int > offsets_for_write()
Span< float2 > surface_uv_coords() const
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
GSpanAttributeWriter lookup_for_write_span(StringRef attribute_id)
Result sample(const float2 &query_uv) const
local_group_size(16, 16) .push_constant(Type b
T mix3(const float3 &weights, const T &v0, const T &v1, const T &v2)
typename DefaultMixerStruct< T >::type DefaultMixer
T mix2(float factor, const T &a, const T &b)
T sample_corner_attribute_with_bary_coords(const float3 &bary_weights, const int3 &corner_tri, const Span< T > corner_attribute)
static void calc_radius_without_interpolation(CurvesGeometry &curves, const IndexRange new_points_range, const float radius)
Vector< NeighborCurve, max_neighbors > NeighborCurves
static Array< NeighborCurves > find_curve_neighbors(const Span< float3 > root_positions, const KDTree_3d &old_roots_kdtree)
void interpolate_from_neighbor_curves(const Span< NeighborCurves > neighbors_per_curve, const T &fallback, const GetValueF &get_value_from_neighbor, MutableSpan< T > r_interpolated_values)
AddCurvesOnMeshOutputs add_curves_on_mesh(bke::CurvesGeometry &curves, const AddCurvesOnMeshInputs &inputs)
static constexpr int max_neighbors
float3 compute_surface_point_normal(const int3 &tri, const float3 &bary_coord, Span< float3 > corner_normals)
static void calc_position_with_interpolation(CurvesGeometry &curves, const Span< float3 > root_positions_cu, const Span< NeighborCurves > neighbors_per_curve, const int old_curves_num, const Span< float > new_lengths_cu, const Span< float3 > new_normals_su, const bke::CurvesSurfaceTransforms &transforms, const Span< int3 > corner_tris, const ReverseUVSampler &reverse_uv_sampler, const Span< float3 > corner_normals_su)
static void calc_radius_with_interpolation(CurvesGeometry &curves, const int old_curves_num, const float radius, const Span< float > new_lengths_cu, const Span< NeighborCurves > neighbors_per_curve)
static void calc_position_without_interpolation(CurvesGeometry &curves, const int old_curves_num, const Span< float3 > root_positions_cu, const Span< float > new_lengths_cu, const Span< float3 > new_normals_su, const float4x4 &surface_to_curves_normal_mat)
static void calc_straight_curve_positions(const float3 &a, const float3 &b, MutableSpan< float3 > dst)
int segments_num(const int points_num, const bool cyclic)
void accumulate_lengths(const Span< T > values, const bool cyclic, MutableSpan< float > lengths)
void sample_at_lengths(Span< float > accumulated_segment_lengths, Span< float > sample_lengths, MutableSpan< int > r_segment_indices, MutableSpan< float > r_factors)
T interpolate(const T &a, const T &b, const FactorT &t)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
VecBase< T, 3 > transform_direction(const MatBase< T, 3, 3 > &mat, const VecBase< T, 3 > &direction)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
MatBase< float, 4, 4 > float4x4
VecBase< float, 2 > float2
VecBase< int32_t, 3 > int3
VecBase< float, 3 > float3
static blender::bke::bNodeSocketTemplate outputs[]
static blender::bke::bNodeSocketTemplate inputs[]
MutableVArraySpan< T > span