Archive for October 2014
3d rotation advice
regarding the pitfalls i encountered implementing 3d rotation..
probably all of them. setting off comfortably from 2d geometry i did not foresee spending over a month on rotation..
the error explained: if you use sine and cosine and radians then you use what game coding people call euler angles. some will say they are correctly called tait-bryan angles, but this is mentioned for reference. i no care.
you may think as i did that you can easily do 3d with what you know but you are horribly WRONG. to illustrate:
here we are in 3d land. we gaze at the back of a tetrahedron. we turn left.. which is accomplished by rotating the world, so that objects on the screen are conveniently aligned with our coordinate system for translating to screen position..
..then, in the 3rd frame, we roll onto our left side some.. if you’re used to the same coordinate system as i, you’d think, “simple, we rotate on the z axis..”
..once we have done this, if we want to turn the camera left or right, what do we do? or to be explicit, incrementing the y angle rotation produces frame 4…
with some consideration it becomes obvious that to accomplish the desired left or right turn once we are rolled, it is going to take some very involved math.
at first i thought, i’ll rotate a unit vector, and decompose that.. then i decided i was being silly and ought to investigate what humans do.
gratifyingly, this turns out to be a classic and charming problem of mathematics. the conventional solutions involve matrix multiplication, or quaternion (specialised matrix) multiplication.
being fundamentally opposed to the introduction of new knowledge, i decided to implement 3 x 3 matrices. they have a floating point problem at the poles of the y axis due to tangency/infinity when translating the matrix back to radian values, but quaternions, for some reason, do not take radian derived arguments..
a matrix takes eg. sin(x) and a quaternion takes sin(x/2). as an audio based coder, if i wanted to do something daft with sin(x), i’d need to take the transcendental twice if i used quaternions. q’s do sound nifty, like a 3d form of the 2d sine oscillator (eg. previous posts), which is something i’d previously wanted to use.
also, everyone tells you to use quaternions, so i used 3 x 3 matrices. there has to be less multiplication as quaternion matrices are 4×4, and that pole error is kinda fun (met it in games).
and here began problem after problem.
there are numerous ways to roll a coordinate system, eg. if x is right and y is up, is z toward you or away from you. do you rotate clockwise or anticlockwise around the axis.. both of these degrees of variation (coordinate system and rotation on axis) have left handed or right handed representations (worth looking up for the visual reference), and the euler-to-matrix composition and decomposition must be structured accordingly.
NASA, the colorado school of mines, et c. et c. have online documentation of 3×3 matrices used with rotation. it’s everywhere, been done for years. however, i’ve been using POVray for 3d modelling for 15 years and am very comfortable with their left hand coordinate system left hand rotation, whereas most of the world use RH/RH.
my desired LH/LH solution was difficult to find online. i direct you to the euler angle pdf at geometrictools.com
ultimately, the solution for “3d rotation from a given orientation” is simple, but the various discrepancies can make it tortuous to implement. especially if you are pig-headed, like me, about keeping things in radian form.. i’m told most 3d games keep orientation in matrix form …ah-soo.. but radians = good for me.
it will not be helpful to list all the problems i had, because others may actually avoid them altogether.. eg. when translating matrix to euler, one axis is returned with pi range instead of 2pi, where rotations are reflected back into the hemisphere by compound effect of the other axes.. if you want a “full spherical response” this can be fixed by checking to see if z is significantly (pi, but not pi*2 of course) different.. when it crosses the y hemisphere, add pi to x and z and do y = pi – y..
my advice – to start, rotate an object, not the camera. it is very difficult to observe a bug from errors. incorrect order of rotations, for instance, wasn’t immediately intuitive.. g’head and implement the whole thing, carefully.. radians to matrix, matrix to radians.. rotate your object using the matrix or a euler angle function.
if you pick an xyz order matrix, you must rotate in zyx order if you use euler rotation. or it will act normal, act normal, woah spin all over the place.
so you have one rotation for object orientation, and another that represents the slight amount of incrementation.. you convert them both to matrices and multiply them together.. i found that the incrementation matrix had to be first, otherwise you get the same result as in the illustration. no one ever told me that! it’s just one of those things that you finally discover needs to be that way.
i wish someone would have told me that.
i wish i’d known things like, “that matrix conversion is right, mess around with that other thing to fix the bug”, but you never have that facility when outsourcing.
looking back at the last five weeks, there were stages where it took time to find the correct search terms to meet my solution, but the greater share of time lost is due to my determination to retain euler angles. or something. i don’t know what i could say or show a past self to make the process easier, it seems like a travesty of getting hung up on things. i’m glad i got through it managing to keep things left handed and in radians, i’m stunned by how painful the process was.
i guess, i hope you’re comfortable using RH/RH.