diff options
author | Mattias Fredriksson <Osares> | 2022-09-18 05:53:58 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2022-09-18 05:53:58 +0300 |
commit | 095516403c48ad1586d732ba2fc8d641827f7572 (patch) | |
tree | 0d6da2a3c0183407f8c43d4a2a78e3bca6a60579 /source/blender/blenkernel/BKE_curves.hh | |
parent | 641bbc820f94668aa0e5beb972d1368475041cc4 (diff) |
Curves: Correct and improve Catmull Rom interpolation
Correct interpolation of integer POD types for Catmull Rom
interpolation as implemented in eaf416693dcb.
**Problem description**
`attribute_math::DefaultMixer<T>::mix_in()` assumes/asserts positive
weights but the basis function for Catmull-Rom splines generates
negative weights (see image in revision). Passing negative weights will
yield correct result as sum(weights) = 1 (after multiplication by 0.5)
but the assert is still triggered in debug builds. This patch adjusts
the behavior by extending the mix functions with mix4(). The benefit
of using mix#() over a DefaultMixer is that the result no longer needs
to be divided by the weight sum, instead utilizing that the basis weight
sum is constant (see plot).
**Changes**
* Added mix4() and updated catmull_rom::interpolate() to use it.
* Removed TODOs from catmull_rom functions.
* Moved mix definitions to be ordered as 2, 3, 4 in the header.
**Implementation specifics**
`catmull_rom::interpolate()` uses a constexpr to differentiate between
POD types which multiplies the result with 0.5 after weighting the
values, this reduces the number of multiplications for 1D, 2D, 3D
vectors (https://godbolt.org/z/8M1z9Pxx6). While this could be
considered unnecessary, I didn't want to change the original behavior
as it could influence performance (did not measure performance here
as this should ensure the logic is ~identical for FP types).
Differential Revision: https://developer.blender.org/D15997
Diffstat (limited to 'source/blender/blenkernel/BKE_curves.hh')
-rw-r--r-- | source/blender/blenkernel/BKE_curves.hh | 21 |
1 files changed, 7 insertions, 14 deletions
diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh index b1581e93491..0d67152dec8 100644 --- a/source/blender/blenkernel/BKE_curves.hh +++ b/source/blender/blenkernel/BKE_curves.hh @@ -709,7 +709,7 @@ void interpolate_to_evaluated(const GSpan src, const Span<int> evaluated_offsets, GMutableSpan dst); -void calculate_basis(const float parameter, float r_weights[4]); +void calculate_basis(const float parameter, float4 &r_weights); /** * Interpolate the control point values for the given parameter on the piecewise segment. @@ -720,22 +720,15 @@ void calculate_basis(const float parameter, float r_weights[4]); template<typename T> T interpolate(const T &a, const T &b, const T &c, const T &d, const float parameter) { - float n[4]; + BLI_assert(0.0f <= parameter && parameter <= 1.0f); + float4 n; calculate_basis(parameter, n); - /* TODO: Use DefaultMixer or other generic mixing in the basis evaluation function to simplify - * supporting more types. */ - if constexpr (!is_same_any_v<T, float, float2, float3, float4, int8_t, int, int64_t>) { - T return_value; - attribute_math::DefaultMixer<T> mixer({&return_value, 1}); - mixer.mix_in(0, a, n[0] * 0.5f); - mixer.mix_in(0, b, n[1] * 0.5f); - mixer.mix_in(0, c, n[2] * 0.5f); - mixer.mix_in(0, d, n[3] * 0.5f); - mixer.finalize(); - return return_value; + if constexpr (is_same_any_v<T, float, float2, float3>) { + /* Save multiplications by adjusting weights after mix. */ + return 0.5f * attribute_math::mix4<T>(n, a, b, c, d); } else { - return 0.5f * (a * n[0] + b * n[1] + c * n[2] + d * n[3]); + return attribute_math::mix4<T>(n * 0.5f, a, b, c, d); } } |