iDevGames Forums

Full Version: Quaternions in 2D
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I'd like to continue this discussion after being scolded in the "How to handle entity rendering" thread for using quaternions to handle rotations in 2D.

First, I totally understand the objections and the fact that quaternions are overkill for 2D, but as worked to replace my rotation handling with scalar angles I ran into a major problem with interpolation. Here's a quote from the originating thread:

warmi Wrote:If you are dealing with 2d then there is no interpolation problem whatsoever ...

Au contraire! The problem is that angles going from -π to π (or 0 to π.2 depending on your preference) can't simply be linearly interpolated when tweening. You need to find the shortest path and adjust the angles to compensate. Even when I thought I had this working I got bad artifacts, and the code was horribly ugly.

After my frustrations with scalar angles I came up with an interim solution: Use a half-quaternion (I'm making up words again, there's probably a real name for this - complex? spinor?) Anyway, I just took my quaternion code and cut it down to the Z and W components, since X and Y were always zero in the 2D cases. The math is greatly simplified, and the interpolation automagically picks the best/shortest path just like a quaternion.

So, anyone care to share a decent scalar angle interpolation function? Or should I just be happy with the half-quaternion deal I got going?
Doesn't a quaternion in 2D simply reduce to ordinary complex numbers?
Frank C. Wrote:After my frustrations with scalar angles I came up with an interim solution: Use a half-quaternion (I'm making up words again, there's probably a real name for this - complex? spinor?) Anyway, I just took my quaternion code and cut it down to the Z and W components, since X and Y were always zero in the 2D cases. The math is greatly simplified, and the interpolation automagically picks the best/shortest path just like a quaternion.

I am terrible at math, but I think Ingemar is right, since ordinary complex numbers should be 2D. As I recall reading about it sometime in my foggy past, the dude that came up with quaternions did what you did, but in reverse -- he was trying to figure out how to extend complex numbers from 2D to 3D. You just trimmed it back down from 3D to 2D, which I *think*, should essentially be the same equation as for a 2D rotation matrix. So theoretically (at least in my limited understanding), what you're doing sounds correct.
Yep. In the 2D case you just use complex numbers and complex multiplication. Very simple. I use it all over the place in Chipmunk to make things fast and simple.
AnotherJake Wrote:I am terrible at math...
Ditto - and even more so...

Thanks for the explanation guys - I recall reading that quaternions were "extended" complex numbers but I never realized how useful plain old complex numbers were for 2D stuff. I should've paid more attention to the Chipmunk source!
Yep, it's pretty simple. Chipmunk uses the following two functions:

Code:
static inline cpVect
cpvrotate(const cpVect v1, const cpVect v2)
{
        return cpv(v1.x*v2.x - v1.y*v2.y, v1.x*v2.y + v1.y*v2.x);
}

static inline cpVect
cpvunrotate(const cpVect v1, const cpVect v2)
{
        return cpv(v1.x*v2.x + v1.y*v2.y, v1.y*v2.x - v1.x*v2.y);
}

Rotation (and inverse) of v1 using v2 as a rotation angle. v2 should be normalized unless you also want it to scale as well.
So if I understand correctly, v2 in those cpvrotate functions are just normals (direction vectors)? That's useful in its own right but I ended up handling things a little differently.

I found this page that pretty much describes it: http://www.euclideanspace.com/maths/alge.../index.htm. I'm using the "Alternative (spinor representation)" and I've settled on calling these "spinors" in my math library to avoid ambiguous usage.
I do something like this:

angle_delta = target_angle-angle
if( angle_delta<-PI ) angle_delta += 2*PI
if( angle_delta> PI ) angle_delta -= 2*PI

angle += angle_delta*speed
Reference URL's