我有一台3D相机,其当前旋转存储为四元数,我无法正确旋转它。我希望相机根据每帧的鼠标移动(第一人称射击式)逐渐围绕其局部轴旋转,但旋转是错误的。它有点起作用,但相机似乎不应该绕其前轴“滚动”。
我使用此功能更新每帧的旋转:
void Camera::rotate(const Quat& q)
{
// m_rot is the current rotation
m_rot = m_rot * q;
}
这是我的四元数乘法函数:
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);
}
我做错了什么,或者这是某种浮点错误的事情?
答案 0 :(得分:7)
找出问题所在。对于像我想要的鼠标控制的第一人称相机,我想围绕局部x轴旋转以向上和向下看,但是全局y轴用于左右看。
所以这对于x轴是正确的:
m_rot = m_rot * q;
但是我需要为y轴做这个:
m_rot = d * m_rot;
答案 1 :(得分:0)
因为我找不到任何工作示例如何使用DirectXMath设置第一人称摄像头,因为我花了两天时间研究我的解决方案,所以我决定在这里发布我的解决方案。也许有人正在研究同样的问题。我的解决方案不是那么优化,但背后的数学应该是正确的。
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;
}