68 const float total_length = accumulated_lengths.
last();
71 mask.to_best_mask_type([&](
const auto mask) {
74 float factor_in_segment;
76 std::clamp(sample_lengths[i], 0.0f, total_length),
80 const float segment_start = segment_i == 0 ? 0.0f : accumulated_lengths[segment_i - 1];
81 const float segment_end = accumulated_lengths[segment_i];
82 const float segment_length = segment_end - segment_start;
84 r_segment_indices[i] = segment_i;
85 r_length_in_segment[i] = factor_in_segment * segment_length;
96 const float total_length = accumulated_lengths.
last();
99 mask.to_best_mask_type([&](
const auto mask) {
101 const float length = sample_lengths[mask[i]];
102 length_parameterize::sample_at_length(accumulated_lengths,
103 std::clamp(length, 0.0f, total_length),
104 r_segment_indices[i],
105 r_factor_in_segment[i],
121 : accumulated_lengths_(
std::move(accumulated_lengths))
132 signature.single_output<
int>(
"Curve Index");
133 signature.single_output<
float>(
"Length in Curve");
142 2,
"Length in Curve");
167 signature.single_input<
int>(
"Curve Index");
184 auto return_default = [&]() {
185 if (!sampled_positions.
is_empty()) {
188 if (!sampled_tangents.is_empty()) {
189 sampled_tangents.fill_indices(
mask, {0, 0, 0});
191 if (!sampled_normals.is_empty()) {
192 sampled_normals.fill_indices(
mask, {0, 0, 0});
197 return return_default();
202 if (
curves.points_num() == 0) {
203 return return_default();
208 if (!sampled_tangents.is_empty()) {
209 evaluated_tangents =
curves.evaluated_tangents();
211 if (!sampled_normals.is_empty()) {
212 evaluated_normals =
curves.evaluated_normals();
215 const VArray<int> curve_indices =
params.readonly_single_input<
int>(0,
"Curve Index");
222 auto sample_curve = [&](
const int curve_i,
const IndexMask mask) {
228 curves.evaluated_lengths_for_curve(curve_i, cyclic[curve_i]),
234 const IndexRange evaluated_points =
curves.evaluated_points_for_curve(curve_i);
235 if (!sampled_positions.
is_empty()) {
236 length_parameterize::interpolate_to_masked<float3>(
237 evaluated_positions.
slice(evaluated_points),
243 if (!sampled_tangents.is_empty()) {
244 length_parameterize::interpolate_to_masked<float3>(
245 evaluated_tangents.
slice(evaluated_points),
indices, factors,
mask, sampled_tangents);
250 if (!sampled_normals.is_empty()) {
251 length_parameterize::interpolate_to_masked<float3>(
252 evaluated_normals.
slice(evaluated_points),
indices, factors,
mask, sampled_normals);
266 indices_per_curve.
add(curve_indices[i], i);
270 for (
const int curve_i : indices_per_curve.
keys()) {
286 const float curves_total_length)
294 auto clamp_fn = std::make_unique<fn::CustomMF_SI_SO<float, float>>(
296 [curves_total_length](
float factor) {
return factor * curves_total_length; },
304 curves.ensure_evaluated_lengths();
309 for (
const int i :
curves.curves_range()) {
310 length +=
curves.evaluated_length_total_for_curve(i, cyclic[i]);
311 curve_lengths[i] =
length;
313 return curve_lengths;
320 params.set_default_remaining_outputs();
326 if (
curves.points_num() == 0) {
327 params.set_default_remaining_outputs();
332 const float total_length = curve_lengths.
last();
333 if (total_length == 0.0f) {
334 params.set_default_remaining_outputs();
342 auto sample_fn = std::make_unique<SampleCurveFunction>(std::move(geometry_set));
344 std::shared_ptr<FieldOperation> sample_op;
345 if (
curves.curves_num() == 1) {
347 {fn::make_constant_field<int>(0), std::move(length_field)});
350 auto index_fn = std::make_unique<SampleFloatSegmentsFunction>(std::move(curve_lengths));
Low-level operations for curves.
@ GEO_COMPONENT_TYPE_CURVE
void node_type_update(struct bNodeType *ntype, void(*updatefunc)(struct bNodeTree *ntree, struct bNode *node))
#define NODE_STORAGE_FUNCS(StorageT)
void nodeSetSocketAvailability(struct bNodeTree *ntree, struct bNodeSocket *sock, bool is_available)
#define NODE_CLASS_GEOMETRY
void node_type_storage(struct bNodeType *ntype, const char *storagename, void(*freefunc)(struct bNode *node), void(*copyfunc)(struct bNodeTree *dest_ntree, struct bNode *dest_node, const struct bNode *src_node))
#define GEO_NODE_SAMPLE_CURVE
void nodeRegisterType(struct bNodeType *ntype)
GeometryNodeCurveSampleMode
@ GEO_NODE_CURVE_SAMPLE_FACTOR
@ GEO_NODE_CURVE_SAMPLE_LENGTH
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to curves
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
const T & last(const int64_t n=0) const
void reinitialize(const int64_t new_size)
MapType::KeyIterator keys() const
Span< Value > lookup(const Key &key) const
void add(const Key &key, const Value &value)
constexpr bool is_empty() const
constexpr void fill_indices(Span< int64_t > indices, const T &value)
constexpr Span slice(int64_t start, int64_t size) const
constexpr const T & last(const int64_t n=0) const
T get_internal_single() const
static CurvesGeometry & wrap(::CurvesGeometry &dna_struct)
static std::shared_ptr< FieldOperation > Create(std::shared_ptr< const MultiFunction > function, Vector< GField > inputs={})
void set_signature(const MFSignature *signature)
const MFSignature & signature() const
void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
static fn::MFSignature create_signature()
SampleCurveFunction(GeometrySet geometry_set)
static fn::MFSignature create_signature()
SampleFloatSegmentsFunction(Array< float > accumulated_lengths)
void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
ccl_gpu_kernel_postfix int ccl_global int * indices
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
void sample_at_length(const Span< float > accumulated_segment_lengths, const float sample_length, int &r_segment_index, float &r_factor, SampleSegmentHint *hint=nullptr)
T clamp(const T &a, const T &min, const T &max)
T length(const vec_base< T, Size > &a)
vec_base< T, Size > normalize(const vec_base< T, Size > &v)
static Array< float > curve_accumulated_lengths(const bke::CurvesGeometry &curves)
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_declare(NodeDeclarationBuilder &b)
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)
static Field< float > get_length_input_field(GeoNodeExecParams params, const GeometryNodeCurveSampleMode mode, const float curves_total_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)
static void node_type_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_geo_exec(GeoNodeExecParams params)
static void node_update(bNodeTree *ntree, bNode *node)
void devirtualize_varray(const VArray< T > &varray, const Func &func, bool enable=true)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
void register_node_type_geo_curve_sample()
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
void node_copy_standard_storage(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
void node_free_standard_storage(bNode *node)
const Curves * get_curves_for_read() const
NodeGeometryExecFunction geometry_node_execute
void(* draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr)
NodeDeclareFunction declare