Euler angle math -- w/o matrices or quats!

Started by
7 comments, last by Futurulus 17 years, 3 months ago
Hey everybody, I'm making a game that takes place in zero-G, which means that "up" and "down" mean nothing. I want my player to rotate around its local axes when WSADEQ are pressed, but unfortunately the engine I'm using only understands Euler angles. So I'm trying to make some functions to accomplish this. The problem is that the engine can't do quaternions, and matrix programming on it is tedious and bug-prone. So I'm trying to do it with trig funcs, etc. I'm looking for something like this:

void ang_rotate_yaxis(angle& ang, double theta)
{
   ang.yaw += /* your complex trig-function etc. formula here*/ ;
   ang.pitch += /* formula here */ ;
   ang.roll += /* formula here */ ;
}
Any ideas? If you need details about the engine, just say so.
Advertisement
I would suggest introducing a matrix library to use for these functions. Do all your rotation stuff with matrices (or quaternions, if you prefer) and then boil them down to Euler angles to submit to the engine.
Quote:Original post by Sneftel
I would suggest introducing a matrix library to use for these functions. Do all your rotation stuff with matrices (or quaternions, if you prefer) and then boil them down to Euler angles to submit to the engine.
Seconded. The type of rotations you wish to perform are best handled via vectors, matrices, or quaternions, not Euler angles.
So you're saying I should make a dll w/ the Cplusplus SDK that came with it? The way the engine is set up (and it's not very flexible), everything has to end up as Euler angles; I can use matrices for intermediate calculations, but I'd have to convert back to do anything.

Just to make sure: to calculate the final transformation matrix, I'd do this, right:

mat_final = my_rotation_matrix * roll_matrix * pitch_matrix * yaw_matrix;

Now that I have that, how do I convert back from there? Sorry, I'm still learning about matrix programming...the script language of this engine is great for learning on but not a very flexible or powerful language. To give you an idea, here's my simple source file that I'm using only to solve this problem:
// "Angle test" source file// A simple room with a ninja in the middle, controlled with the keys WSADQE// The engine uses pan, tilt and roll instead of yaw, pitch, and roll, but the idea's the same.var video_mode = 8; //1024x768var video_screen = 1; //fullscreenstring at_world_wmb = <at_world.wmb>; // level file (a simple cube room with a model in the center)path "C:\\Program Files\\GStudio6\\Billy";path "C:\\Program Files\\GStudio6\\Billy\\eg";var tempvec[3];var tempvec2[3];function main(){	level_load(at_world_wmb);}function ang_rotate_x(&angle, theta) // X axis rotation is pretty simple:{                                    // adjusting the roll does this nicely.	vec_set(tempvec, angle); // The temporary vector thing is just because returning pointers is a nightmare.	tempvec.roll += theta;	vec_set(angle, tempvec);}/* Here's where I'm having trouble...function ang_rotate_y(&angle, theta){	//...}function ang_rotate_z(&angle, theta){	//...}*/function ang_fix(&angle) // Just to keep the numbers simple{	vec_set(tempvec, angle);	tempvec.pan %= 360; // fix pan to 0..360	tempvec.tilt = ang(tempvec.tilt); // fix tilt to -180..180	tempvec.roll %= 360; // fix roll to 0..360	vec_set(angle, tempvec);}action the_player() // Actions are automatically started 2 frames after the level_load instruction in main(){	vec_set(my.x, nullvector); // "my" is sort of like "this": it means the object (the ninja) that was assigned this action.	vec_set(my.pan, nullvector);	player = me; // "player" is a predefined pointer	while(1)	{		if(key_w) { ang_rotate_y(my.pan, 2 * time); }		if(key_s) { ang_rotate_y(my.pan, -2 * time); }		if(key_a) { ang_rotate_z(my.pan, 2 * time); }		if(key_d) { ang_rotate_z(my.pan, -2 * time); }		if(key_e) { ang_rotate_x(my.pan, 2 * time); }		if(key_q) { ang_rotate_x(my.pan, -2 * time); }				vec_for_angle(tempvec, my.pan); // put the camera 50 quants behind the player		vec_inverse(tempvec);           // |		vec_normalize(tempvec, 50);     // |		vec_set(camera.x, tempvec);     // V				vec_set(camera.pan, my.pan); // face the player				ang_fix(my.pan);		ang_fix(camera.pan);				wait(1); // the engine uses function multitasking, so I can get away with an endless loop	}}
Quote:Original post by jyk
Seconded. The type of rotations you wish to perform are best handled via vectors, matrices, or quaternions, not Euler angles.

Wait, vectors? GameStudio has a great vector math library. How would I do this with vectors?
Quote:Original post by Futurulus
Quote:Original post by jyk
Seconded. The type of rotations you wish to perform are best handled via vectors, matrices, or quaternions, not Euler angles.

Wait, vectors? GameStudio has a great vector math library. How would I do this with vectors?
I posted some C++ code here some time ago showing how to implement 6DOF motion using vectors. Perhaps you could adapt it to your needs.

If the API you're using only accepts orientations in Euler-angle form, then you'll also have to perform an Euler-to-matrix conversion, as Sneftel said. The trick will be making sure you use the correct conversion conventions so that the orientations match.
Quote:mat_final = my_rotation_matrix * roll_matrix * pitch_matrix * yaw_matrix;
Yes, either the above or the reverse of the above (i.e. terms in the opposite order) would be correct. Assuming the Euler angle matrices are built about the cardinal axes, the above would be correct for column-vector matrices. Also, the rotation matrices would need to represent rotation deltas (the change in rotation for that update) rather than absolute (accumulated) yaw, pitch, and roll angles.

Finally, in the above example it would be a good idea to orthogonalize mat_final after it's computed.
Quote:Original post by jyk
I posted some C++ code here some time ago showing how to implement 6DOF motion using vectors. Perhaps you could adapt it to your needs.


YES! I'm a total noob at most of this math, but I actually get that code!

Just some stuff I want to make sure of:

  • std::sinf is a simple sine function, nothing fancy, right? I couldn't find it in my standard library reference.

  • m_forward is a space vector pointing along the object's forward axis, right? and similar for m_up and m_side? For my purposes, they don't have to be normalized (although from what I gather from the code, they always are).



I'll try it and get back to you. I don't think I'll even have to use the SDK!

Quote:Original post by Futurulus
  • std::sinf is a simple sine function, nothing fancy, right?
  • Yup. (That's older code - in 'pure' C++ you would just use std::sin(), which may be why you couldn't find sinf().)
    Quote:
  • m_forward is a space vector pointing along the object's forward axis, right? and similar for m_up and m_side? For my purposes, they don't have to be normalized (although from what I gather from the code, they always are).

  • Yes on all counts.
    Quote:I'll try it and get back to you. I don't think I'll even have to use the SDK!
    Let me know if you run into any problems :)
    Allllllmost there...

    It appears to be working, fingers crossed, but one problem left, in boiling the whole thing back down to Euler angles:
    After the axis rotation, I have the resulting m_up, m_side, and m_forward vectors, as well as the correct pan and tilt orientations of the object. How do I get the roll out of these numbers? If the roll in one rotation is wrong, the rest subsequently change, so I'm not totally sure I have the rest of your code right, but I'm hopeful.

    Thanks a lot, you've been really helpful!

    This topic is closed to new replies.

    Advertisement