How to rotate the quaternion along the entire axis?

I want to encode a first-person camera with its rotation stored in a quaternion. Unfortunately, something is wrong with rotation.

To rotate the camera, the following function answers. The Mouse and Speed parameters go through the mouse movement and rotation speed. Then the function selects the quaternion of rotation, rotates it and saves the result. By the way, I am using Bullet Physics , in which types and functions appear.

 void Rotate(vec2 Mouse, float Speed) { btTransform transform = camera->getWorldTransform(); btQuaternion rotation = transform.getRotation(); Mouse = Mouse * Speed; // apply mouse sensitivity btQuaternion change(Mouse.y, Mouse.x, 0); // create quaternion from angles rotation = change * rotation; // rotate camera by that transform.setRotation(rotation); camera->setWorldTransform(transform); } 

To illustrate the resulting rotation of the camera while moving the mouse, I will show you a hand drawing. On the left side, the incorrect rotation that the camera actually performs is displayed. The right case is shown on the right side. The arrows show how the camera rotates when you move the mouse up (orange) and down (blue).

wrong rotation on the left and desired rotation on the right

As you can see, as long as the yaw is zero, the rotation is correct. But the more he has yaw, the less circles around which the camera rotates. On the contrary, circles should always run through the entire sphere, like longitude.

I am not very familiar with quaternions, so here I ask how to rotate them correctly.

+6
c ++ rotation 3d camera quaternions
source share
2 answers

I learned how to properly rotate the quaternion myself. The key was to find the vectors for the axis I want to rotate. They are used to create quaternions along the axis and corner, when the angle is the amount that rotates around the actual axis.

The following code shows what I ended up with. It also allows you to roll the camera, which may be useful for a while.

 void Rotate(btVector3 Amount, float Sensitivity) { // fetch current rotation btTransform transform = camera->getWorldTransform(); btQuaternion rotation = transform.getRotation(); // apply mouse sensitivity Amount *= Sensitivity; // create orientation vectors btVector3 up(0, 1, 0); btVector3 lookat = quatRotate(rotation, btVector3(0, 0, 1)); btVector3 forward = btVector3(lookat.getX(), 0, lookat.getZ()).normalize(); btVector3 side = btCross(up, forward); // rotate camera with quaternions created from axis and angle rotation = btQuaternion(up, Amount.getY()) * rotation; rotation = btQuaternion(side, Amount.getX()) * rotation; rotation = btQuaternion(forward, Amount.getZ()) * rotation; // set new rotation transform.setRotation(rotation); camera->setWorldTransform(transform); } 

Since I rarely found information on quaternion rotation, I will spend some time further explaining the code above.

The extraction and installation of rotation are specific to the physical engine and are not related to this issue, so I will not dwell on this in detail. The next part, multiplying the number by the sensitivity of the mouse, should be really understandable. Let the direction vectors continue.

  • The up vector depends on your own implementation. Most conveniently, the positive Y axis is directed upward, so we get 0, 1, 0 .
  • The lookat vector represents the direction the camera is looking. We simply rotate the unit vector pointing forward using the quaternion of rotation of the camera. Again, the directional vector depends on your agreement. If the Y axis is raised, the positive Z axis can point forward, which is 0, 0, 1 .
  • Do not mix this with the following vector. It is called forward , which refers to the rotation of the camera. Therefore, we just need to project the lookat vector lookat the ground. In this case, we just take the lookat vector and ignore the component pointing up. For accuracy, we normalize this vector.
  • The side vector points to the left of the camera orientation. Therefore, it is perpendicular to both the up and forward , and we can use the cross-product to calculate it.

Given these vectors, we can correctly rotate the camera quaternion around them. Let's start with Z, Y or Z, depending on the sequence of Euler angles , which, again, differs from application to application. Since I want rotation to be applied in YXZ order, I do the following.

  • First, rotate the camera around the up axis by an amount to rotate Y. This is yaw.
  • Then rotate around the side axis, which points to the left, by X. This is a step.
  • Finally, rotate the Z value around the forward vector to apply the roll.

To apply these rotations, we need to multiply the quaternions by the axis and angle with the current rotation of the camera. Finally, we apply the reduced quaternion to the body in physical modeling.

+9
source share

Matrices and pitch / yaw / shaft, which have their own limitations, I no longer use them, but instead use quaternions. I rotate the presentation vector and first recount the camera vectors, and then the view matrix in relation to the vector with the rotation view.

 void Camera::rotateViewVector(glm::quat quat) { glm::quat rotatedViewQuat; quat = glm::normalize(quat); m_viewVector = glm::normalize(m_viewVector); glm::quat viewQuat(0.0f, m_viewVector.x, m_viewVector.y, m_viewVector.z); viewQuat = glm::normalize(viewQuat); rotatedViewQuat = (quat * viewQuat) * glm::conjugate(quat); rotatedViewQuat = glm::normalize(rotatedViewQuat); m_viewVector = glm::normalize(glm::vec3(rotatedViewQuat.x, rotatedViewQuat.y, rotatedViewQuat.z)); m_rightVector = glm::normalize(glm::cross(glm::vec3(0.0f, 1.0f, 0.0f), m_viewVector)); m_upVector = glm::normalize(glm::cross(m_viewVector, m_rightVector)); } 
0
source share

All Articles