Fix #106927: Crash when removing handle position attribute
Bezier curve position evaluation expects the handle position attributes to exist and doesn't handle the case where they don't. Swith to using a utility function to evaluate each curve type so Bezier evaluation can stop early in that case.
This commit is contained in:
@@ -617,65 +617,80 @@ Span<float3> CurvesGeometry::evaluated_positions() const
|
||||
[&](Vector<float3> &r_data) { r_data.clear_and_shrink(); });
|
||||
return this->positions();
|
||||
}
|
||||
this->ensure_nurbs_basis_cache();
|
||||
runtime.evaluated_position_cache.ensure([&](Vector<float3> &r_data) {
|
||||
r_data.resize(this->evaluated_points_num());
|
||||
MutableSpan<float3> evaluated_positions = r_data;
|
||||
|
||||
const OffsetIndices<int> points_by_curve = this->points_by_curve();
|
||||
const OffsetIndices<int> evaluated_points_by_curve = this->evaluated_points_by_curve();
|
||||
const VArray<int8_t> types = this->curve_types();
|
||||
const VArray<bool> cyclic = this->cyclic();
|
||||
const VArray<int> resolution = this->resolution();
|
||||
const Span<float3> positions = this->positions();
|
||||
|
||||
const Span<float3> handle_positions_left = this->handle_positions_left();
|
||||
const Span<float3> handle_positions_right = this->handle_positions_right();
|
||||
const Span<int> all_bezier_offsets = runtime.evaluated_offsets_cache.data().all_bezier_offsets;
|
||||
|
||||
const VArray<int8_t> nurbs_orders = this->nurbs_orders();
|
||||
const Span<float> nurbs_weights = this->nurbs_weights();
|
||||
const Span<curves::nurbs::BasisCache> nurbs_basis_cache = runtime.nurbs_basis_cache.data();
|
||||
|
||||
threading::parallel_for(this->curves_range(), 128, [&](IndexRange curves_range) {
|
||||
for (const int curve_index : curves_range) {
|
||||
const IndexRange points = points_by_curve[curve_index];
|
||||
const IndexRange evaluated_points = evaluated_points_by_curve[curve_index];
|
||||
|
||||
switch (types[curve_index]) {
|
||||
case CURVE_TYPE_CATMULL_ROM:
|
||||
curves::catmull_rom::interpolate_to_evaluated(
|
||||
positions.slice(points),
|
||||
cyclic[curve_index],
|
||||
resolution[curve_index],
|
||||
evaluated_positions.slice(evaluated_points));
|
||||
break;
|
||||
case CURVE_TYPE_POLY:
|
||||
evaluated_positions.slice(evaluated_points).copy_from(positions.slice(points));
|
||||
break;
|
||||
case CURVE_TYPE_BEZIER: {
|
||||
const IndexRange offsets = curves::per_curve_point_offsets_range(points, curve_index);
|
||||
curves::bezier::calculate_evaluated_positions(
|
||||
positions.slice(points),
|
||||
handle_positions_left.slice(points),
|
||||
handle_positions_right.slice(points),
|
||||
all_bezier_offsets.slice(offsets),
|
||||
evaluated_positions.slice(evaluated_points));
|
||||
break;
|
||||
}
|
||||
case CURVE_TYPE_NURBS:
|
||||
curves::nurbs::interpolate_to_evaluated(nurbs_basis_cache[curve_index],
|
||||
nurbs_orders[curve_index],
|
||||
nurbs_weights.slice_safe(points),
|
||||
positions.slice(points),
|
||||
evaluated_positions.slice(evaluated_points));
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
auto evaluate_catmull = [&](const IndexMask selection) {
|
||||
const VArray<bool> cyclic = this->cyclic();
|
||||
const VArray<int> resolution = this->resolution();
|
||||
threading::parallel_for(selection.index_range(), 128, [&](const IndexRange range) {
|
||||
for (const int curve_index : selection.slice(range)) {
|
||||
const IndexRange points = points_by_curve[curve_index];
|
||||
const IndexRange evaluated_points = evaluated_points_by_curve[curve_index];
|
||||
curves::catmull_rom::interpolate_to_evaluated(
|
||||
positions.slice(points),
|
||||
cyclic[curve_index],
|
||||
resolution[curve_index],
|
||||
evaluated_positions.slice(evaluated_points));
|
||||
}
|
||||
});
|
||||
};
|
||||
auto evaluate_poly = [&](const IndexMask selection) {
|
||||
curves::copy_point_data(
|
||||
points_by_curve, evaluated_points_by_curve, selection, positions, evaluated_positions);
|
||||
};
|
||||
auto evaluate_bezier = [&](const IndexMask selection) {
|
||||
const Span<float3> handle_positions_left = this->handle_positions_left();
|
||||
const Span<float3> handle_positions_right = this->handle_positions_right();
|
||||
if (handle_positions_left.is_empty() || handle_positions_right.is_empty()) {
|
||||
curves::fill_points(evaluated_points_by_curve, selection, float3(0), evaluated_positions);
|
||||
return;
|
||||
}
|
||||
});
|
||||
const Span<int> all_bezier_offsets =
|
||||
runtime.evaluated_offsets_cache.data().all_bezier_offsets;
|
||||
threading::parallel_for(selection.index_range(), 128, [&](const IndexRange range) {
|
||||
for (const int curve_index : selection.slice(range)) {
|
||||
const IndexRange points = points_by_curve[curve_index];
|
||||
const IndexRange evaluated_points = evaluated_points_by_curve[curve_index];
|
||||
const IndexRange offsets = curves::per_curve_point_offsets_range(points, curve_index);
|
||||
curves::bezier::calculate_evaluated_positions(
|
||||
positions.slice(points),
|
||||
handle_positions_left.slice(points),
|
||||
handle_positions_right.slice(points),
|
||||
all_bezier_offsets.slice(offsets),
|
||||
evaluated_positions.slice(evaluated_points));
|
||||
}
|
||||
});
|
||||
};
|
||||
auto evaluate_nurbs = [&](const IndexMask selection) {
|
||||
this->ensure_nurbs_basis_cache();
|
||||
const VArray<int8_t> nurbs_orders = this->nurbs_orders();
|
||||
const Span<float> nurbs_weights = this->nurbs_weights();
|
||||
const Span<curves::nurbs::BasisCache> nurbs_basis_cache = runtime.nurbs_basis_cache.data();
|
||||
threading::parallel_for(selection.index_range(), 128, [&](const IndexRange range) {
|
||||
for (const int curve_index : selection.slice(range)) {
|
||||
const IndexRange points = points_by_curve[curve_index];
|
||||
const IndexRange evaluated_points = evaluated_points_by_curve[curve_index];
|
||||
curves::nurbs::interpolate_to_evaluated(nurbs_basis_cache[curve_index],
|
||||
nurbs_orders[curve_index],
|
||||
nurbs_weights.slice_safe(points),
|
||||
positions.slice(points),
|
||||
evaluated_positions.slice(evaluated_points));
|
||||
}
|
||||
});
|
||||
};
|
||||
curves::foreach_curve_by_type(this->curve_types(),
|
||||
this->curve_type_counts(),
|
||||
this->curves_range(),
|
||||
evaluate_catmull,
|
||||
evaluate_poly,
|
||||
evaluate_bezier,
|
||||
evaluate_nurbs);
|
||||
});
|
||||
return runtime.evaluated_position_cache.data();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user