4 ms·
I've been out of the games sphere for a long time, but is slerp() really the default idiomatic interpolation approach in modern games nowadays? There are a van
by Chabsff 5y ago
I've been out of the games sphere for a long time, but is slerp() really the default idiomatic interpolation approach in modern games nowadays?
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.
- an1sotropy 5y agoas for why lerp+normalize isn't enough: it all depends on the distance between things being blended, no? With far away end points, the apparent speed of the rotation would be fast, slow, fast, at the beginning, middle, end, which could be a bummer.
- Chabsff 5y agoThe two aspects that slerp() addresses over lerp() + normalize() are 1) it can deal with pole-to-pole interpolation 2) It always takes the shortest path. 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.
- gugagore 5y agoYou can see what's wrong with that approach by considering the difference between traveling at constant speed along the arc of a circle versus traveling at constant speed along a chord, and projecting the point (out from the center) onto the arc. 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.
- Chabsff 5y ago10-12 years ago, the consensus used to be that this singularity simply does not show up in the wild in the vast majority of scenarios, and the performance hit of using `slerp()` is just not worth it unless truly needed. 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.
- gugagore 5y agoYeah, I understand. I just wanted to show that one can understand the exact nature of the approximation in 2D geometry. 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.
- Chabsff 5y agoMy apologies. I thought you were providing an explanation as to why slerp() is preferred in general. The circle example is a really good way to frame the distinction.
- dahart 5y agoI don’t think the scenarios where uniform steps of angle is vanishingly small. There are plenty of cases where it matters to animators, on character rigs, on cameras 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.