Curves: Simplify calculation of NURBS basis functions
Replaces current basis function calculation which seems to be a direct implementation of the recursive NURBS formulation. New implementation avoids the need to check for zero divisions during iteration. Out of bounds checks are also converted to asserts, assuming input provides valid span index. Performance wise this nets a 7+% performance improvement with the average result being as fast or faster then the fastest execution from previous implementation! Pull Request: https://projects.blender.org/blender/blender/pulls/144457
This commit is contained in:
committed by
Hans Goudey
parent
fff3af04c4
commit
ccd8926717
@@ -190,47 +190,38 @@ Vector<int> calculate_multiplicity_sequence(const Span<float> knots)
|
||||
return multiplicity;
|
||||
}
|
||||
|
||||
/* Basis function calculation, implementation based on 'The NURBS Book' p. 70, ISBN: 3540615458.
|
||||
*/
|
||||
static void calculate_basis_for_point(const Span<float> knots,
|
||||
const int degree,
|
||||
const int wrapped_points_num,
|
||||
const float parameter,
|
||||
const int span_index,
|
||||
MutableSpan<float> r_weights,
|
||||
int &r_start_index)
|
||||
{
|
||||
BLI_assert(degree >= 1);
|
||||
BLI_assert(span_index >= degree);
|
||||
BLI_assert(span_index + degree < knots.size());
|
||||
BLI_assert(knots[span_index + 1] > knots[span_index]);
|
||||
const int order = degree + 1;
|
||||
|
||||
const int start = std::max(span_index - degree, 0);
|
||||
int end = span_index;
|
||||
r_start_index = span_index - degree;
|
||||
|
||||
Array<float, 12> buffer(order * 2, 0.0f);
|
||||
buffer[end - start] = 1.0f;
|
||||
Array<float, 12> left(order);
|
||||
Array<float, 12> right(order);
|
||||
r_weights[0] = 1.0f;
|
||||
|
||||
for (const int i_order : IndexRange(2, degree)) {
|
||||
if (end + i_order >= knots.size()) {
|
||||
end = wrapped_points_num + degree - i_order;
|
||||
}
|
||||
for (const int i : IndexRange(end - start + 1)) {
|
||||
const int knot_index = start + i;
|
||||
|
||||
float new_basis = 0.0f;
|
||||
if (buffer[i] != 0.0f) {
|
||||
new_basis += ((parameter - knots[knot_index]) * buffer[i]) /
|
||||
(knots[knot_index + i_order - 1] - knots[knot_index]);
|
||||
}
|
||||
|
||||
if (buffer[i + 1] != 0.0f) {
|
||||
new_basis += ((knots[knot_index + i_order] - parameter) * buffer[i + 1]) /
|
||||
(knots[knot_index + i_order] - knots[knot_index + 1]);
|
||||
}
|
||||
|
||||
buffer[i] = new_basis;
|
||||
for (const int j : IndexRange(1, degree)) {
|
||||
left[j] = parameter - knots[span_index + 1 - j];
|
||||
right[j] = knots[span_index + j] - parameter;
|
||||
float saved = 0.0f;
|
||||
for (const int r : IndexRange(j)) {
|
||||
const float temp = r_weights[r] / (right[r + 1] + left[j - r]);
|
||||
r_weights[r] = saved + right[r + 1] * temp;
|
||||
saved = left[j - r] * temp;
|
||||
}
|
||||
r_weights[j] = saved;
|
||||
}
|
||||
|
||||
buffer.as_mutable_span().drop_front(end - start + 1).fill(0.0f);
|
||||
r_weights.copy_from(buffer.as_span().take_front(order));
|
||||
r_start_index = start;
|
||||
}
|
||||
|
||||
void calculate_basis_cache(const int points_num,
|
||||
@@ -288,7 +279,6 @@ void calculate_basis_cache(const int points_num,
|
||||
const float parameter = knots[span_index] + step * knot_step;
|
||||
calculate_basis_for_point(knots,
|
||||
degree,
|
||||
wrapped_points_num,
|
||||
parameter,
|
||||
span_index,
|
||||
basis_weights.slice(eval_point * order, order),
|
||||
@@ -300,7 +290,6 @@ void calculate_basis_cache(const int points_num,
|
||||
if (!cyclic) {
|
||||
calculate_basis_for_point(knots,
|
||||
degree,
|
||||
wrapped_points_num,
|
||||
knots[wrapped_points_num],
|
||||
span_offsets.last(),
|
||||
basis_weights.slice(basis_weights.size() - order, order),
|
||||
|
||||
BIN
tests/files/io_tests/obj/all_curves.obj
(Stored with Git LFS)
BIN
tests/files/io_tests/obj/all_curves.obj
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/io_tests/obj/all_curves_as_nurbs.obj
(Stored with Git LFS)
BIN
tests/files/io_tests/obj/all_curves_as_nurbs.obj
(Stored with Git LFS)
Binary file not shown.
@@ -1,4 +1,4 @@
|
||||
# Blender 4.1.0 Alpha MTL File: 'all_objects.blend'
|
||||
# Blender 5.0.0 Alpha MTL File: 'all_objects.blend'
|
||||
# www.blender.org
|
||||
|
||||
newmtl Blue
|
||||
|
||||
BIN
tests/files/io_tests/obj/all_objects.obj
(Stored with Git LFS)
BIN
tests/files/io_tests/obj/all_objects.obj
(Stored with Git LFS)
Binary file not shown.
@@ -1,4 +1,4 @@
|
||||
# Blender 4.1.0 Alpha MTL File: 'all_objects.blend'
|
||||
# Blender 5.0.0 Alpha MTL File: 'all_objects.blend'
|
||||
# www.blender.org
|
||||
|
||||
newmtl Blue
|
||||
|
||||
BIN
tests/files/io_tests/obj/all_objects_mat_groups.obj
(Stored with Git LFS)
BIN
tests/files/io_tests/obj/all_objects_mat_groups.obj
(Stored with Git LFS)
Binary file not shown.
BIN
tests/files/io_tests/obj/nurbs_mesh.obj
(Stored with Git LFS)
BIN
tests/files/io_tests/obj/nurbs_mesh.obj
(Stored with Git LFS)
Binary file not shown.
Reference in New Issue
Block a user