Each entity and camera have a
Transformation object that holds position info as vec3, rotation info as quat and scale info as vec3.
When I need a matrix (that being either model or view matrix), I construct the matrix out of given data. That gives me the freedom to change any of transformation info without having to worry about order of change.
Now, I'm trying to implement it in a fly-camera. The two constraints are pitch that has to be limited from -90° to 90° and roll which should not occur.
While rotating the camera along X and Y axis, a sort of drift happens along the Z axis. In order to combat that, after all changes to rotation are applied, I get the angle of rotation around the Z axis and then rotate it by -angle, effectively resetting the Z-rotation to 0.
That all works nicely in theory, but not so much in practice.
You see, when I go over ~55ish° both in the positive or negative Y-rotation, the camera starts freaking out and fluctuating. It seems that every frame it switches from some negative z rotation, to positive z rotation of the same value. It looks like this (moving camera to the left, negative Y-rotation):
Of course, since the object is only in the one place at one time, I had to edit the screenshot in paint to give you a better idea of what's going on. It really does look like there are two objects at the same time, both flickering as crazy.
Also note that if I were to move camera further to the left, the Z-rotation offset would increase, moving both objects further from the horizontal plane. At this point, the Y-rotation would also start to fluctuate ever so slightly. You couldn't see it on screen, but printing out angle each frame would show that it's fluctuating at about 3rd digit after the dot (0.00####).
Once I get far enough, the camera would just give up and just show the object rapidly changing it's Z-rotation with no apparent pattern.
My guess is that quaternion rotation is imprecise for some reason. You can tell by the fact that my strict Z-rotation starts to influence the Y-rotation after the Z-drift gets severe enough.
Here's a snippet of code, for what it's worth:
transformation->rotateAroundY(angleY); GLfloat roll = transformation->getRoll(); transformation->rotateAroundZ(-roll);
angleY is delta Y of mouse position between this and previous frame.
rotateAround#(angle) calls this code:
rotation *= glm::tquat<GLfloat>(glm::angleAxis(glm::radians(angle), axis));
rotation is the quaternion, while
tvec3<GLfloat> representing the axis around which the rotation takes place.
How do I combat this? How can I consistently reverse unintentional Z-drift without making the camera freak out?