Geometry Nodes: Trim curve node selection input and corrections

Correct trim for cyclical curves mentioned in T101379, splitting the
curves if the start/endpoint is at the 'loop point'.

Correct implementation based on comments in D14481, request was made to
use 'foreach_curve_by_type' to computing the point lookups.

Included corrections from D16066 as it may not be a adopted solution.

Exposed selection input by adding it as input to the node.
Note: This is disabled for 3.4 to avoid making UI changes in Bcon3.

Differential Revision: https://developer.blender.org/D16161
This commit is contained in:
Mattias Fredriksson
2022-11-09 10:50:51 -06:00
committed by Hans Goudey
parent d01187c963
commit 11f6c65e61
5 changed files with 667 additions and 759 deletions

View File

@@ -19,6 +19,7 @@ NODE_STORAGE_FUNCS(NodeGeometryCurveTrim)
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
// b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
b.add_input<decl::Float>(N_("Start"))
.min(0.0f)
.max(1.0f)
@@ -64,6 +65,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
const NodeGeometryCurveTrim &storage = node_storage(*node);
const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)storage.mode;
// bNodeSocket *start_fac = static_cast<bNodeSocket *>(node->inputs.first)->next->next;
bNodeSocket *start_fac = static_cast<bNodeSocket *>(node->inputs.first)->next;
bNodeSocket *end_fac = start_fac->next;
bNodeSocket *start_len = end_fac->next;
@@ -109,6 +111,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static void geometry_set_curve_trim(GeometrySet &geometry_set,
const GeometryNodeCurveSampleMode mode,
Field<bool> &selection_field,
Field<float> &start_field,
Field<float> &end_field)
{
@@ -123,41 +126,21 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set,
bke::CurvesFieldContext field_context{src_curves, ATTR_DOMAIN_CURVE};
fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
evaluator.add(selection_field);
evaluator.add(start_field);
evaluator.add(end_field);
evaluator.evaluate();
const VArray<float> starts = evaluator.get_evaluated<float>(0);
const VArray<float> ends = evaluator.get_evaluated<float>(1);
const VArray<bool> cyclic = src_curves.cyclic();
const IndexMask selection = evaluator.get_evaluated_as_mask(0);
const VArray<float> starts = evaluator.get_evaluated<float>(1);
const VArray<float> ends = evaluator.get_evaluated<float>(2);
/* If node length input is on form [0, 1] instead of [0, length]*/
const bool normalized_length_lookup = mode == GEO_NODE_CURVE_SAMPLE_FACTOR;
/* Stack start + end field. */
Vector<float> length_factors(src_curves.curves_num() * 2);
Vector<int64_t> lookup_indices(src_curves.curves_num() * 2);
threading::parallel_for(src_curves.curves_range(), 512, [&](IndexRange curve_range) {
for (const int64_t curve_i : curve_range) {
const bool negative_trim = !cyclic[curve_i] && starts[curve_i] > ends[curve_i];
length_factors[curve_i] = starts[curve_i];
length_factors[curve_i + src_curves.curves_num()] = negative_trim ? starts[curve_i] :
ends[curve_i];
lookup_indices[curve_i] = curve_i;
lookup_indices[curve_i + src_curves.curves_num()] = curve_i;
}
});
/* Create curve trim lookup table. */
Array<bke::curves::CurvePoint, 12> point_lookups = geometry::lookup_curve_points(
src_curves, length_factors, lookup_indices, normalized_length_lookup);
if (selection.is_empty()) {
return;
}
bke::CurvesGeometry dst_curves = geometry::trim_curves(
src_curves,
src_curves.curves_range().as_span(),
point_lookups.as_span().slice(0, src_curves.curves_num()),
point_lookups.as_span().slice(src_curves.curves_num(), src_curves.curves_num()));
src_curves, selection, starts, ends, mode);
Curves *dst_curves_id = bke::curves_new_nomain(std::move(dst_curves));
bke::curves_copy_parameters(src_curves_id, *dst_curves_id);
geometry_set.replace_curves(dst_curves_id);
@@ -171,18 +154,20 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
GeometryComponentEditData::remember_deformed_curve_positions_if_necessary(geometry_set);
// Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
Field<bool> selection_field = fn::make_constant_field<bool>(true);
if (mode == GEO_NODE_CURVE_SAMPLE_FACTOR) {
Field<float> start_field = params.extract_input<Field<float>>("Start");
Field<float> end_field = params.extract_input<Field<float>>("End");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
geometry_set_curve_trim(geometry_set, mode, start_field, end_field);
geometry_set_curve_trim(geometry_set, mode, selection_field, start_field, end_field);
});
}
else if (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) {
Field<float> start_field = params.extract_input<Field<float>>("Start_001");
Field<float> end_field = params.extract_input<Field<float>>("End_001");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
geometry_set_curve_trim(geometry_set, mode, start_field, end_field);
geometry_set_curve_trim(geometry_set, mode, selection_field, start_field, end_field);
});
}