There are a vanishingly small number of scenarios where lerp() + normalize() doesn't work perfectly well enough and it is drastically faster and SIMD-friendly. That used to be the case at least.
There are a vanishingly small number of scenarios where lerp() + normalize() doesn't work perfectly well enough and it is drastically faster and SIMD-friendly. That used to be the case at least.
It works great if the chord is far away from the center (and also the angle is less than a half turn). If the chord goes through the center, it doesn't work at all.
It was essentially the same reasoning as for using `-ffast-math`. Yeah it's not "correct", but users can't tell the difference and it has a measurable performance benefit.
To be clear, I'm not questioning using slerp() at all, it definitely has a role to play. I'm just wondering about using it by default as implied by the post.
I think it's useful to think of it as a separate category of "wrong" than -ffast-math, which is "wrong" because two expressions that are mathematically equivalent over real numbers, like a + (b + c) and (a + b) + c, are not equivalent over floating-point numbers.
Using lerp in place of slerp is like using x in place of sin(x). (The small-angle approximation) They're not equivalent over the real numbers.
The amount that it matters depends on the angle between keys. Suggesting it rarely matters means you’re claiming nobody ever animates large angles, which I can confidently say I’ve seen plenty of counter-examples in game development.
I also wouldn’t be so sure that lerp+normalize is that much faster on today’s GPUs. Normalize takes a sqrt and reciprocal or divide, while slerp takes a few sin evaluations and a recip or divide. These special functions these days execute in a separate pipeline from linear (FMA) type instructions, and can be had for “free” as long as you can mix enough independent linear math in between the special functions. It used to be that sin() was very slow, but these days you can often mix a couple calls in without affecting your perf at all.
In practice, the former is often provably never going to happen, and the later doesn't actually matter from a qualitative standpoint: Quaternion interpolation will always look a bit weird over large angles, especially if there's a roll component to one of the orientations.
As far as having a constant interpolation speed: again, this is rarely perceptible, and truly linear transitions from one orientation to another looks janky so some amount of filtering happens anyways (an ease-in-ease-out for example).
But yeah, for very large interpolations, it can create a slight authoring/runtime skew. My rule of thumb used to be: use slerp() when the orientations can be at least 120 degrees apart, or when lerp() yields weird results. However, it's really rare to be interpolating over such a large orientation change, you almost always have a few keyframes or dead-reckoning syncs in between.
Again: This might be an outdated perspective though.