Curves: Remove attribute retrieval, deduplicate evaluation logic

Avoid calling `interpolate_to_evaluate` while evaluating normals,
which has to look up attributes by name for every curve. Also avoid
duplicating the curve type switch in a few functions. I didn't observe
a performance difference, but theoretically this could reduce
overhead for many small curves.
This commit is contained in:
Hans Goudey 2023-01-17 14:40:01 -06:00
parent dcb37959d4
commit 301119619c
1 changed files with 81 additions and 54 deletions

View File

@ -716,14 +716,57 @@ static void rotate_directions_around_axes(MutableSpan<float3> directions,
}
}
static void evaluate_generic_data_for_curve(
const int curve_index,
const IndexRange points,
const VArray<int8_t> &types,
const VArray<bool> &cyclic,
const VArray<int> &resolution,
const Span<int> bezier_evaluated_offsets,
const Span<curves::nurbs::BasisCache> nurbs_basis_cache,
const VArray<int8_t> &nurbs_orders,
const Span<float> nurbs_weights,
const GSpan src,
GMutableSpan dst)
{
switch (types[curve_index]) {
case CURVE_TYPE_CATMULL_ROM:
curves::catmull_rom::interpolate_to_evaluated(
src, cyclic[curve_index], resolution[curve_index], dst);
break;
case CURVE_TYPE_POLY:
dst.copy_from(src);
break;
case CURVE_TYPE_BEZIER:
curves::bezier::interpolate_to_evaluated(src, bezier_evaluated_offsets.slice(points), dst);
break;
case CURVE_TYPE_NURBS:
curves::nurbs::interpolate_to_evaluated(nurbs_basis_cache[curve_index],
nurbs_orders[curve_index],
nurbs_weights.slice_safe(points),
src,
dst);
break;
}
}
Span<float3> CurvesGeometry::evaluated_normals() const
{
this->runtime->normal_cache_mutex.ensure([&]() {
const Span<float3> evaluated_tangents = this->evaluated_tangents();
const VArray<int8_t> types = this->curve_types();
const VArray<bool> cyclic = this->cyclic();
const VArray<int8_t> normal_mode = this->normal_mode();
const VArray<int8_t> types = this->curve_types();
const VArray<int> resolution = this->resolution();
const VArray<int8_t> nurbs_orders = this->nurbs_orders();
const Span<float> nurbs_weights = this->nurbs_weights();
const Span<float3> evaluated_tangents = this->evaluated_tangents();
const VArray<float> tilt = this->tilt();
VArraySpan<float> tilt_span;
const bool use_tilt = !(tilt.is_single() && tilt.get_internal_single() == 0.0f);
if (use_tilt) {
tilt_span = tilt;
}
this->runtime->evaluated_normal_cache.resize(this->evaluated_points_num());
MutableSpan<float3> evaluated_normals = this->runtime->evaluated_normal_cache;
@ -748,19 +791,26 @@ Span<float3> CurvesGeometry::evaluated_normals() const
/* If the "tilt" attribute exists, rotate the normals around the tangents by the
* evaluated angles. We can avoid copying the tilts to evaluate them for poly curves. */
if (!(tilt.is_single() && tilt.get_internal_single() == 0.0f)) {
if (use_tilt) {
const IndexRange points = this->points_for_curve(curve_index);
Span<float> curve_tilt = tilt.get_internal_span().slice(points);
if (types[curve_index] == CURVE_TYPE_POLY) {
rotate_directions_around_axes(evaluated_normals.slice(evaluated_points),
evaluated_tangents.slice(evaluated_points),
curve_tilt);
tilt_span.slice(points));
}
else {
evaluated_tilts.clear();
evaluated_tilts.resize(evaluated_points.size());
this->interpolate_to_evaluated(
curve_index, curve_tilt, evaluated_tilts.as_mutable_span());
evaluated_tilts.reinitialize(evaluated_points.size());
evaluate_generic_data_for_curve(curve_index,
points,
types,
cyclic,
resolution,
this->runtime->bezier_evaluated_offsets.as_span(),
this->runtime->nurbs_basis_cache.as_span(),
nurbs_orders,
nurbs_weights,
tilt_span.slice(points),
evaluated_tilts.as_mutable_span());
rotate_directions_around_axes(evaluated_normals.slice(evaluated_points),
evaluated_tangents.slice(evaluated_points),
evaluated_tilts.as_span());
@ -781,27 +831,17 @@ void CurvesGeometry::interpolate_to_evaluated(const int curve_index,
const IndexRange points = this->points_for_curve(curve_index);
BLI_assert(src.size() == points.size());
BLI_assert(dst.size() == this->evaluated_points_for_curve(curve_index).size());
switch (this->curve_types()[curve_index]) {
case CURVE_TYPE_CATMULL_ROM:
curves::catmull_rom::interpolate_to_evaluated(
src, this->cyclic()[curve_index], this->resolution()[curve_index], dst);
return;
case CURVE_TYPE_POLY:
dst.type().copy_assign_n(src.data(), dst.data(), src.size());
return;
case CURVE_TYPE_BEZIER:
curves::bezier::interpolate_to_evaluated(
src, this->runtime->bezier_evaluated_offsets.as_span().slice(points), dst);
return;
case CURVE_TYPE_NURBS:
curves::nurbs::interpolate_to_evaluated(this->runtime->nurbs_basis_cache[curve_index],
this->nurbs_orders()[curve_index],
this->nurbs_weights().slice_safe(points),
src,
dst);
return;
}
BLI_assert_unreachable();
evaluate_generic_data_for_curve(curve_index,
points,
this->curve_types(),
this->cyclic(),
this->resolution(),
this->runtime->bezier_evaluated_offsets.as_span(),
this->runtime->nurbs_basis_cache.as_span(),
this->nurbs_orders(),
this->nurbs_weights(),
src,
dst);
}
void CurvesGeometry::interpolate_to_evaluated(const GSpan src, GMutableSpan dst) const
@ -818,30 +858,17 @@ void CurvesGeometry::interpolate_to_evaluated(const GSpan src, GMutableSpan dst)
for (const int curve_index : curves_range) {
const IndexRange points = this->points_for_curve(curve_index);
const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
switch (types[curve_index]) {
case CURVE_TYPE_CATMULL_ROM:
curves::catmull_rom::interpolate_to_evaluated(src.slice(points),
cyclic[curve_index],
resolution[curve_index],
dst.slice(evaluated_points));
continue;
case CURVE_TYPE_POLY:
dst.slice(evaluated_points).copy_from(src.slice(points));
continue;
case CURVE_TYPE_BEZIER:
curves::bezier::interpolate_to_evaluated(
src.slice(points),
this->runtime->bezier_evaluated_offsets.as_span().slice(points),
dst.slice(evaluated_points));
continue;
case CURVE_TYPE_NURBS:
curves::nurbs::interpolate_to_evaluated(this->runtime->nurbs_basis_cache[curve_index],
nurbs_orders[curve_index],
nurbs_weights.slice_safe(points),
src.slice(points),
dst.slice(evaluated_points));
continue;
}
evaluate_generic_data_for_curve(curve_index,
points,
types,
cyclic,
resolution,
this->runtime->bezier_evaluated_offsets,
this->runtime->nurbs_basis_cache,
nurbs_orders,
nurbs_weights,
src.slice(points),
dst.slice(evaluated_points));
}
});
}