Game Development Community

Worth using quaternions for Players?

by Daniel Buckmaster · in Torque Game Engine · 12/25/2008 (12:27 pm) · 14 replies

I've been looking into player rotations and stuff, and I can't help thinking that porting the entire Player rotation system into quaternions would make it all a bit easier. However, is it really worth it? I'm thinking I will be using them for characters walking on walls/ceilings (a la AVP) occasionally, as well as players conforming to the terrain a little more often.
Given that most of the time, players won't be making use of any strange rotation, is it a significant waste of resources to use quaternions? I think I'll go ahead and make the changes anyway - it should be a great learning experience.
Maybe the chnages can be relegated to a Player subclass, which can be used for players who require extraordinary rotation.

About the author

Studying mechatronic engineering and computer science at the University of Sydney. Game development is probably my most time-consuming hobby!


#1
12/25/2008 (12:56 pm)
You'll run into gimbal locks without a Quaternation, if you don't implement custom stuff for Euler of course. We went with quaternations.
#2
12/25/2008 (5:52 pm)
Players work well with being rotated for any purpose (terrain conforming, walking on walls, etc...) until they get close to perpendicular with the Z axis, or upside down. Once you hit that, the camera will first stop rotating the way it should, and once your are upside-down, invert. It also creates a ton of glitches with collision and contact due to the way the Player class' collisions are optimized to assume the player's upAxis is always (0,0,-1). So you'll not only need to rewrite the player class, but the specialized convex class it uses as well.

I tried doing this a while ago, but never got to finishing it. Maybe you'll have better determination.
#3
12/25/2008 (6:08 pm)
I haven't bothered to touch this side of the engine, but wouldn't it help to look into how the vehicles, especially the flying ones, how they managed all axis movement or does that just make things worse? I assumed the flying vehicles already used quaternion math for movement calculations anyway.
#4
12/26/2008 (1:31 am)
All right, thanks for the info guys.
Stefan - good to know someone's already done this. I assume successfully ;)
Morrock - yeah, I've already started seeing places where it's assumed the player is pointing straight up... my first thought about the issue was simply to implement an 'up' vector per player, and then their mRot.z would be in terms of rotation around that vector. Then I realised that this basically is a quaternion, no?
Nathan - I'll do that, thanks for the pointer.
#5
12/27/2008 (1:24 pm)
Okay, I've done what little I can, and have *sort of* got climbing ladders working. Ish. Butthe problem is that I'm really not well-enough grounded on the use of quaternions in games to replace the entire rotation system. I've used quaternions to concatenate rotations and avoid gimbal lock, but I've got no idea how I should be using them to represent, for example, turning 45 degrees left.
Nathan - I checked the vehicle code, but they don't really do anything with quternions. They just pas it all off into their rigid's angular position. I guess I'll need to check that out, then...
Morrock - I'm having trouble understanding the Player's convex collision system. As far as I can tell, the player's transform is used in most calculations involving its bounding box, so that should take care of rotation, shouldn't it?
#6
12/27/2008 (7:06 pm)
It took me a week and quite alot of frustration, but it worked out in the end. Basically copy-pasted large parts of Vehicle and then started to take away things I didn't think was of any use (center of mass and all that).

Quote:
As far as I can tell, the player's transform is used in most calculations involving its bounding box, so that should take care of rotation, shouldn't it?

The Player's collision system is custom and optimized to not care about the bounding box's rotation.
It's simple to change this, but then you still have one issue left, and that's when you only rotate the box and not move, in which case you can rotate into another convex and get stuck. In this case, it's easier to use something else than the Extruded collision scheme.

Again, I ended up looking at others work here to get our spacecraft working. So I tried out the Tank Pack and figured it was working well in that regard, looked at their code and adapted it to our codebase. It wasn't simple for me, but worth it in the end.

Quote:
They just pas it all off into their rigid's angular position. I guess I'll need to check that out, then...

Yeah, it's a bugger to read. What I did was to get *all* the Rigid code into Vehicle and then just not use Rigid. From there, I started slimming it down to the basics that I needed. Much simpler to understand this way!
#7
12/27/2008 (7:06 pm)
Nathan has a point here, but I would actually suggest looking at grounded vehicles and the Vehicle class most. Though they all use Quat's, I found these ones the most interesting. With just a few lines of code changed to modify the direction of a vehicles gravitational force to be based on a vector I had set up in the ShapeBase class, vehicles were able to drive entirely around things like planet shaped, well...Shapes.

Vehicles work perfectly with any sort of transform, and yes Daniel, they do use QuatF's to keep track of their rotational position. They do pass a bit off of it to their Rigid in order for it to keep track of, and to do the simulation math for it. But that just means you should probably also look at how Rigid's do math for Quaternions. Also, you wouldn't need to implement an upVector for Players as that should already be stored in their transform. You just need to make it so the transform is manipulated properly.

As far as the Player Convex goes, they use an orthoBoxConvex. I'm a bit behind on my Matrix and Quaternion math, so I don't know everything about it, but I know this: the mOrthoMatrixCache for the OrthoBoxConvex appears to be what is uses as it's transform. Or at least what it returns as it's transform. Aside form the position column, this is purely an identity Matrix, meaning if you try to use getTransform() for the Player's convex, the only value returned that is actually based on the Player is the position column. The X-vector is full X, Y-vector is full y, Z vector is full Z. So this pretty much means that it is axis-aligned, and it's edges point only in the direction of the axis (including straight Z), eh?

Also, I think there are a few places where the engine sets up a box as if it were axis aligned for collision detection purposes. I'm not sure if this is to assume the player is straight upwards, or just AABB broadphasing; I haven't really looked at those. As well as in the findContact function the interestNormal for a clippedPolyList is set to (0,0,-1).
#8
01/07/2009 (8:59 am)
Phew, I'm getting in deep here :P.

Stefan: rotation is definitely one area that will be a problem. I know next to nothing about collision detection/resolution, though :P. I'm thinking I'll go with your idea and just use the Rigid stuff. Not sure what sort of performance hit that entails - I guess it depends how much of Rigid I end up using.

I'm wondering whether, since transform matrices are so tightly integrated, I should use an axis/angle solution instead of quats. I just realised that they aren't the same thing :P. But axis/angle works very well for my purpose, and it might be a little simpler to deal with than replacing everything with quats. Plus, they don't suffer gimbal lock, so that's dealt with.

Morrock: thanks for the info... that vehicle change seems to be one I'll want to make as well. What's that vehicle in UT3 that sticks to everything? :P And yep, I just realised reading through the code that that would kind of be redundant... I need to decide on a direction and implement that from the ground up, rather than just adding things on.

Thank you as well for the information in the convex... that'll be something to change :P. I wonder if convexes are designed to be axis aligned? But in that case, they wouldn't ned a transform.

EDIT: Just for fun, I replaced the Player's OrthoBoxConvex with a regular BoxConvex. Things still seem to work as they should, and I'm assuming that now the box will at least be aligned correctly. Since the only thing OrthoBoxConvex seems to do is get rid of transform. I'm wondering whether this will create problems for Players...
#9
01/07/2009 (2:58 pm)
Quote:I'm thinking I'll go with your idea and just use the Rigid stuff. Not sure what sort of performance hit that entails - I guess it depends how much of Rigid I end up using.
If you do this, at least make sure to only use a convex of 6 sides (a box), tune the integration down to 1 for greatest efficiency of the Rigid, and make sure there is no restitution (or else your player will bounce around on collision response).

UT3? Haven't played that one, though I still play UT2K4 to an unhealthy extent :D. And I bet you could recreate that same vehicle in Torque in less than 100 lines of code (not including the datablocks for the vehicle).
#10
01/08/2009 (8:56 am)
Yep, physics shall be a minimum :P. I was actually just going to see ho much of Rigid I could rip out to apply to Players - including integration and all that. De[ending on how necessary it is. The main things are the collision detection and quaternions.
Aftyer doing a little more reading, I've become a little clearer on how to use quats for rotation. I'm thinking Player::updateMove will need to look like:

-Get yaw and pitch from move
-Get a matrix from our orientation quat
-Compose a rotation quaternion of yaw degrees about our up vector
-Multiply our orientation quat by the rotation quat?
-Get a matrix again to use for movement directions

Having to make two matrices irks me, but I haven't had a good think about how to get around it :P. But then in getTransform and getRenderTransform we have to convert our orientation quat into a matrix. I'm guessing that in interpolateTick we should slerp two orientation quats? And to comform the player to the terrain, we need to get a 'desired orientation' quat from the surface normal somehow.

Oh about the vehicle, I'm not actually sure since I haven't played it either :P. But I've heard things.
#11
01/08/2009 (9:32 am)
Trust me Daniel, you don't have to (and shouldn't) use Rigid for this stuff. But you can use it to learn how to implement this yourself. When I began, I had all of Rigid in my player class, but I just didn't like the looks of it and slowly started to rip out stuff I didn't need. I always made sure nothing broke, and kept working on it.

Finally, there was maybe 20 or so lines left in Rigid and I decided it was time to bring it into Player instead of having it in a seperate class. Now it's 6 lines in Player::updatePos () and a few scattered changes and definitions. Really simple stuff. The only hassle was packing the new rotational stuff and interpolation, but I felt motivated as soon as I saw that no gimbal locks occured anymore so I kept hammering at it until it worked.

I'm really swamped with stuff at work, and got a few contracts pending still but I would love to release this as a resource eventually, and hopefully soon enough. It's really really simple once you get down to it, but I have to seperate it out from our Player class and talk to my coworkers before releasing anything.

To be perfectly clear:

Integration is just a way to avoid doing physics too often and waste cycles. Quaternational rotation has nothing to do with that and I'm not even sure it's more heavy than using Euler, it's just a little bit more akward to work with.

Rigid is so much more than just QuatF and rotation :) That's why it has integration.

Center of Mass is another thing I wanted to get rid of, since I just wanted a Player with the exact same properties as a normal one, just that it could rotate in any direction without gimbal locking. If that's what you want too, then you shouldn't bother with integration, center of mass, or anything of that - honestly.
#12
01/08/2009 (11:36 am)
Okay, I didn't make my intentions fully clear. I don't want to make the Player use rigid-body physics with a linked Rigid object like vehicles. I just took what I thought you'd done, which was implemented a Rigid-like solution for Players based on the vehicle system, and then stripped it dwn to the bare minimum. Like you say, I do really just want quaternion rotation.
Which actually turned out simpler to implement than I anticipated. I figured I'd just give it a shot, and lo and behold, I *think* it's working. At least, it behaves like the player used to. Which was totally unexpected, given how often my code solutions work, especially ones where I'm in the mindset of 'let's see what happens...' I'm still checking to see whether I'm actually running the most recently compiled code :P
Basically what I did was pick through the code, using a quaternion mOrient whenever mRot was used previously. I made new updatePosition functions that take a point and a quat for an argument, and use these where previously it used two points (well, one point and one Euler rotation).
I haven't done anything interesting (like rotating off the vertical :P) with it yet, but soon...

Anyway, I will definitely be making this a resource if I get it working and tested properly. It'd be interesting to compare our solutions ;)

Next up is rotational collision, I guess...

EDIT: Interpolation is also an area I've run into trouble with. I've just left it for now. I'm having trouble understanding warping, backstepping, etc :P.
#13
01/08/2009 (1:50 pm)
I vaguely remember QuatF's doing their own interpolation or something like that, but can't remember.

Warping is when position on server and client differs, and you set the new position on client a warp will occur. A warp is instant and more noticable than interpolating between two positions, though interpolation between two points that are far apart doesn't look nice, either.

AFAIK, backstepping happens when the client has extrapolated too much (I didn't think Torque did extrapolation? Perhaps this is only done on the control object, since we're one tick in advance here, preprocessing moves..) and the Player didn't infact move like the client predicted.

Rotational collision is a huge pain in the ar*e. If you want pointers the tank pack is excellent in this case as it implements this trough a ClippedPolyList!
#14
01/09/2009 (7:49 am)
Yep, quats have a SLERP method already. This is how I interpolate between two previous orientations. Thanks for the explanations... I guess I just need to read the code more. Even if the purpose of warming, etc., is clear, how it is accomplished with the move struct isn't. There's a lot of different variables being tracked there...

Ah, maybe I'll skip that aspect of collision :P. I want to go pack-free as much as possible, partly so I can make everything I want into a resource, and partly because I want to pay for as little as possible :P If I remember rightly, the CSK guys got some sort of rotation collisionfor Player images, didn't they? So that you don't get images penetrating walls.