jgrams: I did, I'm using loads and loads of particles because I need to and they're as performant as I could make them. They're an important part of the game. But using sin/cos for each of 2k particles
in Flash would be overkill.
Even if it wouldn't turn to be an issue, being a nerd and all I'd like to know if there's a super cheap way with splines and complex numbers
Gosh, this got long. tl;dr: Jonathon Blow's article is excellent: basically he's doing a normalized lerp with a fast approximate normalization and is using a polynomial for `t` to smooth out the uneven distribution of the lerp.OK, well, let me talk through what I know then...This is
relatively basic and I'm guessing you know most of it, but maybe it will be useful to someone...
Disclaimer: this is off the top of my head, so you'll want to check it. And my terminology is
horribly sloppy here: ignore that.
You can represent orientations by complex numbers (x + iy), where `i` is the imaginary unit (square root of -1). Then rotating is simply multiplying two complex numbers: the one representing the point to be rotated and the one representing the rotation.
An easy and less "mathy" way of thinking about this is to think of an orientation vector as being the direction of the rotated x-axis. Then in 2D the perpendicular of (a, b) is (-b, a), so you can use that as the new y-axis. To rotate a point P=(px, py), you do px*x_axis + py*y_axis. Collecting the "real" x and y factors, we get:
px2 = px*a - py*b
py2 = px*b + py*a
If you have a rotation `a+bi`, you can rotate in the opposite direction by multiplying by the complex conjugate `a-bi`.
Note that these orientation vectors are supposed to have length 1: otherwise multiplying by one will scale as well as rotate. Also note that they are cos(angle) + i*sin(angle).
Now, linear interpolation is the most basic way of blending two values. If you have two values `a` and `b`, and a blending parameter t which goes from 0 to 1, then the linear interpolation is:
We can do this with vectors, including our orientation vectors. But it interpolates in a straight line. So instead of going around the outside of the circle, it cuts straight across (forming a chord). So the farther apart your vectors are, the worse an approximation it is. If the vectors are directly opposite each other, it will be useless as it just cuts through the center of the circle. For this reason, some people use angle/2 instead of angle to generate their rotation vectors. Then you have to multiply twice to get the full rotation, but it packs a full 360 degrees into half a circle and avoids that nasty glitch in the interpolation.
We can (somewhat) adjust for the problems of linear interpolation by normalizing the result (scaling it back up so it has length 1 again). That at least keeps it on the circle, but they will be unevenly spaced along the circle (since they are evenly spaced along the chord).
So what Jonathan Blow is doing in that article is doing a normalized lerp and using a polynomial ("spline") to adjust the value of t. Basically he found a polynomial which counteracts the unevenness of distribution that the lerp produces.
So Instead of going linearly from 0 to 1, he defines `t' = 2kt^2 + 3kt + 1 + k`, where `k=0.507 * (1 - 0.788 * cos(alpha))` and alpha is the difference between the two angles you're interpolating between. Note that cos(alpha) is the dot product of the two unit vectors...but you're only doing it once for each pair of vectors, and I'm guessing that you're generating lots of particles for each pair? So it shouldn't be
too expensive.
He's also using an approximation to the inverse square root for the normalization step.
I recommend you read it (if you haven't already): he has good diagrams and so on: I think it's fairly easy to follow.
I also wonder if you couldn't roll it all into one. Instead of using t and 1-t in the lerp, come up with a pair of functions which take t and compute a `ta` and a `tb` which would both smooth the unevenness and give a roughly normalized vector in one step? It would be interesting to play with, anyway.
HTH,
--Josh