Quaternion camera. How do I make it rotate correctly?

匿名 (未验证) 提交于 2019-12-03 02:52:02

问题:

I have a 3D camera with its current rotation stored as a quaternion, and I'm having trouble rotating it correctly. I want the camera to rotate incrementally around its local axes based on mouse movement each frame (first-person-shooter-style), but the rotation is wrong. It kind of works, but the camera seems to "roll" around its forward axis when it shouldn't.

I update the rotation each frame with this function:

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

Here's 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 floating-point error thing?

回答1:

Figured out the problem. For a mouse-controled first-person camera like the one I'm going for, I want to rotate around the local x-axis to look up and down, but the global y-axis for looking side to side.

So this is correct for the x-axis:

m_rot = m_rot * q; 

But I need to do this for the y-axis:

m_rot = d * m_rot; 


回答2:

Because I could not find any working example how to set up a first person camera using DirectXMath and because I spent two days working on my solution I decided to post my solution here. Perhaps there is anyone who is working on the same problem. My solution is not that optimized but the math behind it should 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; } 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!