diff options
5 files changed, 94 insertions, 61 deletions
diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh index fc1292e3620..dfbe82f31fd 100644 --- a/source/blender/blenkernel/BKE_spline.hh +++ b/source/blender/blenkernel/BKE_spline.hh @@ -172,6 +172,25 @@ class Spline { blender::Array<float> sample_uniform_index_factors(const int samples_size) const; LookupResult lookup_data_from_index_factor(const float index_factor) const; + void sample_based_on_index_factors(const blender::fn::GVArray &src, + blender::Span<float> index_factors, + blender::fn::GMutableSpan dst) const; + template<typename T> + void sample_based_on_index_factors(const blender::VArray<T> &src, + blender::Span<float> index_factors, + blender::MutableSpan<T> dst) const + { + this->sample_based_on_index_factors( + blender::fn::GVArray_For_VArray(src), index_factors, blender::fn::GMutableSpan(dst)); + } + template<typename T> + void sample_based_on_index_factors(blender::Span<T> src, + blender::Span<float> index_factors, + blender::MutableSpan<T> dst) const + { + this->sample_based_on_index_factors(blender::VArray_For_Span(src), index_factors, dst); + } + /** * Interpolate a virtual array of data with the size of the number of control points to the * evaluated points. For poly splines, the lifetime of the returned virtual array must not @@ -179,6 +198,13 @@ class Spline { */ virtual blender::fn::GVArrayPtr interpolate_to_evaluated_points( const blender::fn::GVArray &source_data) const = 0; + blender::fn::GVArrayPtr interpolate_to_evaluated_points(blender::fn::GSpan data) const; + template<typename T> + blender::fn::GVArray_Typed<T> interpolate_to_evaluated_points(blender::Span<T> data) const + { + return blender::fn::GVArray_Typed<T>( + this->interpolate_to_evaluated_points(blender::fn::GSpan(data))); + } protected: virtual void correct_end_tangents() const = 0; diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc index 11620a30948..9f8c215b31f 100644 --- a/source/blender/blenkernel/intern/spline_base.cc +++ b/source/blender/blenkernel/intern/spline_base.cc @@ -16,6 +16,7 @@ #include "BLI_array.hh" #include "BLI_span.hh" +#include "BLI_task.hh" #include "BLI_timeit.hh" #include "BKE_spline.hh" @@ -27,6 +28,12 @@ using blender::float3; using blender::IndexRange; using blender::MutableSpan; using blender::Span; +using blender::fn::GMutableSpan; +using blender::fn::GSpan; +using blender::fn::GVArray; +using blender::fn::GVArray_For_GSpan; +using blender::fn::GVArray_Typed; +using blender::fn::GVArrayPtr; Spline::Type Spline::type() const { @@ -234,8 +241,7 @@ Span<float3> Spline::evaluated_normals() const calculate_normals_z_up(tangents, normals); /* Rotate the generated normals with the interpolated tilt data. */ - blender::fn::GVArray_Typed<float> tilts{ - this->interpolate_to_evaluated_points(blender::fn::GVArray_For_Span(this->tilts()))}; + GVArray_Typed<float> tilts = this->interpolate_to_evaluated_points(this->tilts()); for (const int i : normals.index_range()) { normals[i] = rotate_direction_around_axis(normals[i], tangents[i], tilts[i]); } @@ -341,3 +347,34 @@ void Spline::bounds_min_max(float3 &min, float3 &max, const bool use_evaluated) minmax_v3v3_v3(min, max, position); } } + +GVArrayPtr Spline::interpolate_to_evaluated_points(GSpan data) const +{ + return this->interpolate_to_evaluated_points(GVArray_For_GSpan(data)); +} + +/** + * Sample any input data with a value for each evaluated point (already interpolated to evaluated + * points) to arbitrary parameters in betwen the evaluated points. The interpolation is quite + * simple, but this handles the cyclic and end point special cases. + */ +void Spline::sample_based_on_index_factors(const GVArray &src, + Span<float> index_factors, + GMutableSpan dst) const +{ + BLI_assert(src.size() == this->evaluated_points_size()); + + blender::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { + using T = decltype(dummy); + const GVArray_Typed<T> src_typed = src.typed<T>(); + MutableSpan<T> dst_typed = dst.typed<T>(); + blender::parallel_for(dst_typed.index_range(), 1024, [&](IndexRange range) { + for (const int i : range) { + const LookupResult interp = this->lookup_data_from_index_factor(index_factors[i]); + dst_typed[i] = blender::attribute_math::mix2(interp.factor, + src_typed[interp.evaluated_index], + src_typed[interp.next_evaluated_index]); + } + }); + }); +} diff --git a/source/blender/blenkernel/intern/spline_nurbs.cc b/source/blender/blenkernel/intern/spline_nurbs.cc index cae206341a0..bfb0d652b1a 100644 --- a/source/blender/blenkernel/intern/spline_nurbs.cc +++ b/source/blender/blenkernel/intern/spline_nurbs.cc @@ -26,6 +26,7 @@ using blender::float3; using blender::IndexRange; using blender::MutableSpan; using blender::Span; +using blender::fn::GVArray_Typed; SplinePtr NURBSpline::copy() const { @@ -434,10 +435,9 @@ Span<float3> NURBSpline::evaluated_positions() const const int eval_size = this->evaluated_points_size(); evaluated_position_cache_.resize(eval_size); - blender::fn::GVArray_Typed<float3> evaluated_positions{ - this->interpolate_to_evaluated_points(blender::fn::GVArray_For_Span<float3>(positions_))}; - - evaluated_positions->materialize(evaluated_position_cache_); + /* TODO: Avoid copying the evaluated data from the temporary array. */ + GVArray_Typed<float3> evaluated = Spline::interpolate_to_evaluated_points(positions_.as_span()); + evaluated->materialize(evaluated_position_cache_); position_cache_dirty_ = false; return evaluated_position_cache_; diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc index 684f7d6c702..9d0820eb0b0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc @@ -76,34 +76,17 @@ struct SampleModeParam { std::optional<int> count; }; -template<typename T> -static void sample_span_to_output_spline(const Spline &input_spline, - Span<float> index_factors, - const VArray<T> &input_data, - MutableSpan<T> output_data) -{ - BLI_assert(input_data.size() == input_spline.evaluated_points_size()); - - parallel_for(output_data.index_range(), 1024, [&](IndexRange range) { - for (const int i : range) { - const Spline::LookupResult interp = input_spline.lookup_data_from_index_factor( - index_factors[i]); - output_data[i] = blender::attribute_math::mix2(interp.factor, - input_data[interp.evaluated_index], - input_data[interp.next_evaluated_index]); - } - }); -} - static SplinePtr resample_spline(const Spline &input_spline, const int count) { std::unique_ptr<PolySpline> output_spline = std::make_unique<PolySpline>(); output_spline->set_cyclic(input_spline.is_cyclic()); output_spline->normal_mode = input_spline.normal_mode; - if (input_spline.evaluated_edges_size() < 1) { - output_spline->resize(1); - output_spline->positions().first() = input_spline.positions().first(); + if (input_spline.evaluated_edges_size() < 1 || count == 1) { + output_spline->add_point(input_spline.positions().first(), + input_spline.tilts().first(), + input_spline.radii().first()); + output_spline->attributes.reallocate(1); return output_spline; } @@ -111,26 +94,18 @@ static SplinePtr resample_spline(const Spline &input_spline, const int count) Array<float> uniform_samples = input_spline.sample_uniform_index_factors(count); - { - GVArray_For_Span positions(input_spline.evaluated_positions()); - GVArray_Typed<float3> positions_typed(positions); - sample_span_to_output_spline<float3>( - input_spline, uniform_samples, positions_typed, output_spline->positions()); - } - { - GVArrayPtr interpolated_data = input_spline.interpolate_to_evaluated_points( - GVArray_For_Span(input_spline.radii())); - GVArray_Typed<float> interpolated_data_typed{*interpolated_data}; - sample_span_to_output_spline<float>( - input_spline, uniform_samples, interpolated_data_typed, output_spline->radii()); - } - { - GVArrayPtr interpolated_data = input_spline.interpolate_to_evaluated_points( - GVArray_For_Span(input_spline.tilts())); - GVArray_Typed<float> interpolated_data_typed{*interpolated_data}; - sample_span_to_output_spline<float>( - input_spline, uniform_samples, interpolated_data_typed, output_spline->tilts()); - } + input_spline.sample_based_on_index_factors<float3>( + input_spline.evaluated_positions(), uniform_samples, output_spline->positions()); + + input_spline.sample_based_on_index_factors<float>( + input_spline.interpolate_to_evaluated_points(input_spline.radii()), + uniform_samples, + output_spline->radii()); + + input_spline.sample_based_on_index_factors<float>( + input_spline.interpolate_to_evaluated_points(input_spline.tilts()), + uniform_samples, + output_spline->tilts()); output_spline->attributes.reallocate(count); input_spline.attributes.foreach_attribute( @@ -147,16 +122,12 @@ static SplinePtr resample_spline(const Spline &input_spline, const int count) BLI_assert_unreachable(); return false; } - GVArrayPtr interpolated_attribute = input_spline.interpolate_to_evaluated_points( - GVArray_For_GSpan(*input_attribute)); - attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) { - using T = decltype(dummy); - GVArray_Typed<T> interpolated_attribute_typed{*interpolated_attribute}; - sample_span_to_output_spline<T>(input_spline, - uniform_samples, - interpolated_attribute_typed, - (*output_attribute).typed<T>()); - }); + + input_spline.sample_based_on_index_factors( + *input_spline.interpolate_to_evaluated_points(*input_attribute), + uniform_samples, + *output_attribute); + return true; }, ATTR_DOMAIN_POINT); @@ -177,7 +148,7 @@ static std::unique_ptr<CurveEval> resample_curve(const CurveEval &input_curve, else if (mode_param.mode == GEO_NODE_CURVE_SAMPLE_LENGTH) { BLI_assert(mode_param.length); const float length = spline->length(); - const int count = length / *mode_param.length; + const int count = std::max(int(length / *mode_param.length), 1); output_curve->add_spline(resample_spline(*spline, count)); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc index fe1b23bf6d7..b6f04352929 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc @@ -181,8 +181,7 @@ static void spline_extrude_to_mesh_data(const Spline &spline, Span<float3> normals = spline.evaluated_normals(); Span<float3> profile_positions = profile_spline.evaluated_positions(); - GVArray_Typed<float> radii{ - spline.interpolate_to_evaluated_points(blender::fn::GVArray_For_Span(spline.radii()))}; + GVArray_Typed<float> radii = spline.interpolate_to_evaluated_points(spline.radii()); for (const int i_ring : IndexRange(spline_vert_len)) { float4x4 point_matrix = float4x4::from_normalized_axis_data( positions[i_ring], normals[i_ring], tangents[i_ring]); |