[Bf-blender-cvs] [6bcda04d1f1] master: Geometry Nodes: Port sample curves node to new data-block
Hans Goudey
noreply at git.blender.org
Fri Jul 22 17:04:52 CEST 2022
Commit: 6bcda04d1f1cc396dcc188678997105b09231bde
Author: Hans Goudey
Date: Fri Jul 22 09:59:28 2022 -0500
Branches: master
https://developer.blender.org/rB6bcda04d1f1cc396dcc188678997105b09231bde
Geometry Nodes: Port sample curves node to new data-block
Use the newer more generic sampling and interpolation functions
developed recently (ab444a80a280) instead of the `CurveEval` type.
Functions are split up a bit more internally, to allow a separate mode
for supplying the curve index directly in the future (T92474).
In one basic test, the performance seems mostly unchanged from 3.1.
Differential Revision: https://developer.blender.org/D14621
===================================================================
M source/blender/blenlib/BLI_length_parameterize.hh
M source/blender/functions/FN_field.hh
M source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
===================================================================
diff --git a/source/blender/blenlib/BLI_length_parameterize.hh b/source/blender/blenlib/BLI_length_parameterize.hh
index 1b494c021a3..d81bcbe1e7a 100644
--- a/source/blender/blenlib/BLI_length_parameterize.hh
+++ b/source/blender/blenlib/BLI_length_parameterize.hh
@@ -6,6 +6,7 @@
* \ingroup bli
*/
+#include "BLI_index_mask.hh"
#include "BLI_math_base.hh"
#include "BLI_math_color.hh"
#include "BLI_math_vector.hh"
@@ -41,26 +42,38 @@ void accumulate_lengths(const Span<T> values, const bool cyclic, MutableSpan<flo
}
template<typename T>
-inline void interpolate(const Span<T> src,
- const Span<int> indices,
- const Span<float> factors,
- MutableSpan<T> dst)
+inline void interpolate_to_masked(const Span<T> src,
+ const Span<int> indices,
+ const Span<float> factors,
+ const IndexMask dst_mask,
+ MutableSpan<T> dst)
{
BLI_assert(indices.size() == factors.size());
- BLI_assert(indices.size() == dst.size());
+ BLI_assert(indices.size() == dst_mask.size());
const int last_src_index = src.size() - 1;
- for (const int i : dst.index_range()) {
- const int prev_index = indices[i];
- const float factor = factors[i];
- const bool is_cyclic_case = prev_index == last_src_index;
- if (is_cyclic_case) {
- dst[i] = math::interpolate(src.last(), src.first(), factor);
+ dst_mask.to_best_mask_type([&](auto dst_mask) {
+ for (const int i : IndexRange(dst_mask.size())) {
+ const int prev_index = indices[i];
+ const float factor = factors[i];
+ const bool is_cyclic_case = prev_index == last_src_index;
+ if (is_cyclic_case) {
+ dst[dst_mask[i]] = math::interpolate(src.last(), src.first(), factor);
+ }
+ else {
+ dst[dst_mask[i]] = math::interpolate(src[prev_index], src[prev_index + 1], factor);
+ }
}
- else {
- dst[i] = math::interpolate(src[prev_index], src[prev_index + 1], factor);
- }
- }
+ });
+}
+
+template<typename T>
+inline void interpolate(const Span<T> src,
+ const Span<int> indices,
+ const Span<float> factors,
+ MutableSpan<T> dst)
+{
+ interpolate_to_masked(src, indices, factors, dst.index_range(), dst);
}
/**
diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh
index a8136d06c5f..bc42cab8db5 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -221,6 +221,17 @@ class FieldOperation : public FieldNode {
const MultiFunction &multi_function() const;
const CPPType &output_cpp_type(int output_index) const override;
+
+ static std::shared_ptr<FieldOperation> Create(std::shared_ptr<const MultiFunction> function,
+ Vector<GField> inputs = {})
+ {
+ return std::make_shared<FieldOperation>(FieldOperation(std::move(function), inputs));
+ }
+ static std::shared_ptr<FieldOperation> Create(const MultiFunction &function,
+ Vector<GField> inputs = {})
+ {
+ return std::make_shared<FieldOperation>(FieldOperation(function, inputs));
+ }
};
class FieldContext;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
index 01cf1d8db52..e80b600a740 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
@@ -1,8 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BLI_task.hh"
+#include "BLI_devirtualize_parameters.hh"
+#include "BLI_length_parameterize.hh"
-#include "BKE_spline.hh"
+#include "BKE_curves.hh"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -58,34 +59,103 @@ static void node_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, length, mode == GEO_NODE_CURVE_SAMPLE_LENGTH);
}
-template<typename T> static T sample_with_lookup(const Spline::LookupResult lookup, Span<T> data)
+static void sample_indices_and_lengths(const Span<float> accumulated_lengths,
+ const Span<float> sample_lengths,
+ const IndexMask mask,
+ MutableSpan<int> r_segment_indices,
+ MutableSpan<float> r_length_in_segment)
{
- return attribute_math::mix2(
- lookup.factor, data[lookup.evaluated_index], data[lookup.next_evaluated_index]);
+ const float total_length = accumulated_lengths.last();
+ length_parameterize::SampleSegmentHint hint;
+
+ mask.to_best_mask_type([&](const auto mask) {
+ for (const int64_t i : mask) {
+ int segment_i;
+ float factor_in_segment;
+ length_parameterize::sample_at_length(accumulated_lengths,
+ std::clamp(sample_lengths[i], 0.0f, total_length),
+ segment_i,
+ factor_in_segment,
+ &hint);
+ const float segment_start = segment_i == 0 ? 0.0f : accumulated_lengths[segment_i - 1];
+ const float segment_end = accumulated_lengths[segment_i];
+ const float segment_length = segment_end - segment_start;
+
+ r_segment_indices[i] = segment_i;
+ r_length_in_segment[i] = factor_in_segment * segment_length;
+ }
+ });
+}
+
+static void sample_indices_and_factors_to_compressed(const Span<float> accumulated_lengths,
+ const Span<float> sample_lengths,
+ const IndexMask mask,
+ MutableSpan<int> r_segment_indices,
+ MutableSpan<float> r_factor_in_segment)
+{
+ const float total_length = accumulated_lengths.last();
+ length_parameterize::SampleSegmentHint hint;
+
+ mask.to_best_mask_type([&](const auto mask) {
+ for (const int64_t i : IndexRange(mask.size())) {
+ const float length = sample_lengths[mask[i]];
+ length_parameterize::sample_at_length(accumulated_lengths,
+ std::clamp(length, 0.0f, total_length),
+ r_segment_indices[i],
+ r_factor_in_segment[i],
+ &hint);
+ }
+ });
}
+/**
+ * Given an array of accumulated lengths, find the segment indices that
+ * sample lengths lie on, and how far along the segment they are.
+ */
+class SampleFloatSegmentsFunction : public fn::MultiFunction {
+ private:
+ Array<float> accumulated_lengths_;
+
+ public:
+ SampleFloatSegmentsFunction(Array<float> accumulated_lengths)
+ : accumulated_lengths_(std::move(accumulated_lengths))
+ {
+ static fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static fn::MFSignature create_signature()
+ {
+ fn::MFSignatureBuilder signature{"Sample Curve Index"};
+ signature.single_input<float>("Length");
+
+ signature.single_output<int>("Curve Index");
+ signature.single_output<float>("Length in Curve");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
+ {
+ const VArraySpan<float> lengths = params.readonly_single_input<float>(0, "Length");
+ MutableSpan<int> indices = params.uninitialized_single_output<int>(1, "Curve Index");
+ MutableSpan<float> lengths_in_segments = params.uninitialized_single_output<float>(
+ 2, "Length in Curve");
+
+ sample_indices_and_lengths(accumulated_lengths_, lengths, mask, indices, lengths_in_segments);
+ }
+};
+
class SampleCurveFunction : public fn::MultiFunction {
private:
/**
- * The function holds a geometry set instead of a curve or a curve component in order to
- * maintain a reference to the geometry while the field tree is being built, so that the
- * curve is not freed before the function can execute.
+ * The function holds a geometry set instead of curves or a curve component reference in order
+ * to maintain a ownership of the geometry while the field tree is being built and used, so
+ * that the curve is not freed before the function can execute.
*/
GeometrySet geometry_set_;
- /**
- * To support factor inputs, the node adds another field operation before this one to multiply by
- * the curve's total length. Since that must calculate the spline lengths anyway, store them to
- * reuse the calculation.
- */
- Array<float> spline_lengths_;
- /** The last member of #spline_lengths_, extracted for convenience. */
- const float total_length_;
public:
- SampleCurveFunction(GeometrySet geometry_set, Array<float> spline_lengths)
- : geometry_set_(std::move(geometry_set)),
- spline_lengths_(std::move(spline_lengths)),
- total_length_(spline_lengths_.last())
+ SampleCurveFunction(GeometrySet geometry_set) : geometry_set_(std::move(geometry_set))
{
static fn::MFSignature signature = create_signature();
this->set_signature(&signature);
@@ -93,7 +163,8 @@ class SampleCurveFunction : public fn::MultiFunction {
static fn::MFSignature create_signature()
{
- blender::fn::MFSignatureBuilder signature{"Curve Sample"};
+ blender::fn::MFSignatureBuilder signature{"Sample Curve"};
+ signature.single_input<int>("Curve Index");
signature.single_input<float>("Length");
signature.single_output<float3>("Position");
signature.single_output<float3>("Tangent");
@@ -104,11 +175,11 @@ class SampleCurveFunction : public fn::MultiFunction {
void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
{
MutableSpan<float3> sampled_positions = params.uninitialized_single_output_if_required<float3>(
- 1, "Position");
+ 2, "Po
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list