Quaternion Camera. How to make it rotate correctly?

I have a three-dimensional camera with the current rotation stored as a quaternion, and I am having problems setting it up correctly. I want the camera to gradually rotate around its local axes based on the movement of the mouse in each frame (first-person shooter style), but the rotation is wrong. It seems to work, but the camera seems to roll around its front axle when it shouldn't.

I update every frame with this function:

void Camera::rotate(const Quat& q) { // m_rot is the current rotation m_rot = m_rot * q; } 

Here is my quaternion multiplication function:

 Quat Quat::operator*(const Quat &rhs) const { // quaternion elements in w,x,y,z order Vector4d res; res[0] = m_q[0]*rhs.m_q[0] - m_q[1]*rhs.m_q[1] - m_q[2]*rhs.m_q[2] - m_q[3]*rhs.m_q[3]; res[1] = m_q[0]*rhs.m_q[1] + m_q[1]*rhs.m_q[0] + m_q[2]*rhs.m_q[3] - m_q[3]*rhs.m_q[2]; res[2] = m_q[0]*rhs.m_q[2] - m_q[1]*rhs.m_q[3] + m_q[2]*rhs.m_q[0] + m_q[3]*rhs.m_q[1]; res[3] = m_q[0]*rhs.m_q[3] + m_q[1]*rhs.m_q[2] - m_q[2]*rhs.m_q[1] + m_q[3]*rhs.m_q[0]; return Quat(res); } 

Am I doing something wrong, or is this some kind of error with an error?

+8
c ++ math rotation 3d
source share
2 answers

I found out the problem. For a camera with the first person controlled by the mice, like the one I'm going to, I want to rotate around the local x axis to look up and down, but the global y axis to view from the side.

So this is true for the x axis:

 m_rot = m_rot * q; 

But I need to do this for the y axis:

 m_rot = d * m_rot; 
+7
source share

Since I could not find any working example of how to configure the first-person camera using DirectXMath, and because I spent two days on my solution, I decided to post my solution here. Perhaps there is someone who is working on the same issue. My solution is not optimized, but the math behind it must be correct.

 inline DX11FRAMEWORK_API DirectX::XMFLOAT4X4 MatrixCameraFirstPersonQuaternion(DirectX::XMFLOAT3 &Pos, DirectX::XMFLOAT3 &DeltaPos, DirectX::XMFLOAT3 &DeltaAngles, DirectX::XMVECTOR &RotationQuaternion, DirectX::XMFLOAT3 *At = nullptr, DirectX::XMFLOAT3 *Up = nullptr) { using namespace DirectX; static const XMFLOAT3 OriginalAt = { 1.f, 0.f, 0.f }; static const XMFLOAT3 OriginalUp = { 0.f, 1.f, 0.f }; static const XMFLOAT3 OriginalRight = { 0.f, 0.f, 1.f }; // performing rotation of x-axis (here roll) und z-axis (here pitch) round camera axis using quaternion RotationQuaternion = XMQuaternionMultiply(RotationQuaternion, XMQuaternionRotationRollPitchYaw(DeltaAngles.z, 0.f, -DeltaAngles.x)); // performing rotation of y-axis (yaw) round world axis XMMATRIX MRotation = XMMatrixMultiply(XMMatrixRotationQuaternion(RotationQuaternion), XMMatrixRotationRollPitchYaw(0.f, -DeltaAngles.y, 0.f)); // keep track of rotation round y-axis because it is rotated round world axis DeltaAngles = { 0.f, DeltaAngles.y, 0.f }; // generating camera axis XMFLOAT3 CameraAt, CameraRight, CameraUp; XMStoreFloat3(&CameraAt, XMVector3TransformCoord(XMLoadFloat3(&OriginalAt), MRotation)); XMStoreFloat3(&CameraRight, XMVector3TransformCoord(XMLoadFloat3(&OriginalRight), MRotation)); XMStoreFloat3(&CameraUp, XMVector3TransformCoord(XMLoadFloat3(&OriginalUp), MRotation)); // performing translation Pos += CameraAt * DeltaPos.x; Pos += CameraUp * DeltaPos.y; Pos += CameraRight * DeltaPos.z; DeltaPos = { 0.f, 0.f, 0.f }; CameraAt += Pos; if (At) *At = CameraAt; if (Up) *Up = CameraUp; // finally generate view matrix DirectX::XMFLOAT4X4 Camera; DirectX::XMStoreFloat4x4(&Camera, DirectX::XMMatrixLookAtLH(DirectX::XMLoadFloat3(&Pos), DirectX::XMLoadFloat3(&CameraAt), DirectX::XMLoadFloat3(&CameraUp))); return Camera; } 
0
source share

All Articles