On a different question, the user that answered (Ricky) me also said the following (which I still find a little confusing):
When I say they must remain
perpendicular, I only mean that if you
rotate vectors independently by the
same transformation over and over,
floating point errors may creep in and
they could diverge from being
perpendicular. Dot(x,y), dot(y,z) and
dot(x,z) should be very close to zero.
If not, you need to do some cross
products and re-perpendicularize them.
It’s as simple as overwriting
z=cross(x,y), then y=cross(z,x).
There are 3 relevant vectors on my camera system, these vectors are floating point numbers and always normalized. Reference vector points in the direction the camera is looking at, UpVector and RightVector are self-explanatory.
Anyone knowing how to answer, should answer of course, but Ricky, if you’re there, please help me out…
1) What exactly does it mean dot(x,y), dot(y,z) and dot(x,z)? Is this the dot product between these vectors? I suppose… But which ones (x, y, z) correspond to my Reference, UpVector and RightVector? I’m a little confused…
2) Then, these dot products should be very close to zero, how exactly should I check this? I’ve seen code like this to achieve the same thing in a similar context:
const float Math::EPSILON = 1e-6f;
Math::closeEnough(<floating_point_variable_to_check>, 0.0f);
static bool closeEnough(float f1, float f2) {
// Determines whether the two floating-point values f1 and f2 are
// close enough together that they can be considered equal.
return fabsf((f1 - f2) / ((f2 == 0.0f) ? 1.0f : f2)) < EPSILON;
}
I suppose it’s good enough?
3) Where I exactly should I perform all these checks and re-perpendicularize the vectors? I have 3 functions that rotate the camera, Pitch, Yaw and Roll (the last one I don’t use it that much), only these functions change those unit vectors. Should I perform the checks and fixes every time I call one of these rotate functions or would that be too much? Where and when then?
4) Last but not least, to fix them I need to overwrite the vectors with the cross product, makes sense as I want them perpendicular to each other. But isn’t the quote above missing one cross product? And does the order i which I perform those fixes matter?
Hopefully the two current answers are adequate, so I’ll just add on a theoretical note that the reason this arises and the reason it’s not too important how you handle it is that the nine numbers that form a 3×3 rotation matrix and describe how your camera is oriented are more than necessary.
A rotation matrix is just a matrix with the three vectors (e.g. up, right, forward) as the three columns. Consider a matrix with three vectors e1=right, e2=up, e3=backward. Then to transform a point into the same reference frame as the matrix, you premultiply the column vector by
(Or the inverse… I always get the language confused depending on how you think about it. Also, OpenGL uses 4×4 matrices as a trick to apply translations or even perspective with just one matrix.) Anyway, you can get any of the three vectors by crossing two others. i.e.
e1 = e2 x e3,e2 = e3 x e1, ande3 = e1 x e2That means one vector is unnecessary. One less vector leaves six numbers. The length of the two remaining vectors is irrelevant —— only the direction is important — which leaves four numbers required to describe the transformation. Enter quaternions. They’re a mathematical tool that happen to deal with the remaining four numbers in a stable, robust way. If you use all nine numbers though, you just need to make sure that the vectors always have length 1 and that any one is perpendicular to the other two. Otherwise it’s not really a rotation matrix. Up might not be 90 degrees from right. That’s why I suggested:You can do this in any order or combination as long as it accomplishes the same effect. Every iteration or every thousand. If you neglect it completely there’s a small chance that your camera will start to distort the image. After a few camera rotations, only the last couple digits will be modified, so think of it as a fudge factor to keep things from drifting over long periods of time.