I created a camera based on quaternions, but when I turn the camera, an unwanted roll appears. I would not like to lose my freedom of movement using, for example, Euler angles, since there is a need to add roll from time to time. If I use Euler angles, then, as far as I know, I can get a gimbal lock.
Code:
struct FreeCamera : public BaseCamera {
float pitch = 0, yaw = 0, roll = 0;
void updateView();
private:
glm::quat qCamera;
};
struct FreeCameraController: public BaseCameraController {
float sensitivityPitch = 0.0025f, sensitivityYaw = 0.0025f, sensitivityRoll = 0.0025f;
void mouseMove(const float x, const float y, const float z = 0);
inline void setMousePos(const float x, const float y, const float z = 0) {
lastMousePos = glm::vec3(x, y, z);
}
private:
glm::vec3 lastMousePos = glm::vec3(0.0f);
};
void FreeCamera::updateView() {
// temporary frame quaternion from pitch, yaw, roll
glm::quat qPYR = glm::quat(glm::vec3(pitch, yaw, roll));
// reset values
pitch = yaw = roll = 0;
// update qCamera
qCamera = qPYR * qCamera;
qCamera = glm::normalize(qCamera);
glm::mat4 rotate = glm::mat4_cast(qCamera);
glm::mat4 translate = glm::mat4(1.0f);
translate = glm::translate(translate, -pos);
view = rotate * translate;
}
void FreeCameraController::mouseMove(const float x, const float y, const float z) {
glm::vec3 dCoord = glm::vec3(x, y, z) - lastMousePos;
((FreeCamera*)camera)->yaw = dCoord.x * sensitivityYaw;
((FreeCamera*)camera)->pitch = dCoord.y * sensitivityPitch;
((FreeCamera*)camera)->roll = dCoord.z * sensitivityRoll;
lastMousePos = glm::vec3(x, y, z);
}
Is it possible to reset unwanted roll, "stabilize" the camera?
As you want to block roll (and if its a car, possibly yaw too since you will make the car fly), you must block one of the axis by concatenating the rotations. What you want to achieve is the actual Gimbal's lock (you use a single quaternion containing all the rotations when flying specifically to get rid of it). So, assuming you can detect wether the vehicle is on the ground or not:
glm::mat4 rotationMatrix;
// When you want to get rid of any axis rotation, you must lock it
if(onGround)
{
glm::quat yawQ = glm::quat(glm::vec3(0.0f, yaw, 0.0f));
yawQ = glm::normalize(yawQ);
glm::mat4 yawMat = glm::mat4_cast(yawQ);
glm::quat pitch = glm::quat(glm::vec3(pitch, 0.0f, 0.0f));
pitch = glm::normalize(pitch);
glm::mat4 pitchMat = glm::mat4_cast(pitch);
rotationMatrix = pitchMat * yawMat;
}
else
{
//Your computation
rotationMatrix = glm::mat4_cast(yourQuaternion);
}
viewMatrix = rotationMatrix * translationMatrix;
Note that it is not necessary to use quaternions to achieve the gound control effect