如何在DirectX 11中更改四元数旋转以使用本地相机轴而不是世界轴

时间:2017-02-04 16:23:32

标签: c++ camera rotation directx quaternions

我正在尝试基于键盘/鼠标输入围绕其本地轴旋转相机,我目前使用的代码使用DirectXMath并且运行良好,但它使用世界轴旋转而不是相机本地轴。因此,一些旋转不是预期的,并且在相机旋转时会引起问题。例如,当我们倾斜相机时,Y轴会发生变化,我们会想要围绕另一个轴旋转以获得我们预期的结果。

我在代码中做错了什么或者我需要更改什么才能围绕其本地轴旋转?

vector.x,vector.y,vector.z(要旋转的矢量,即(1.0f,0.0f,0.0f))

//define our camera matrix
XMFLOAT4X4 cameraMatrix;

//position, lookat, up values for the camera
XMFLOAT3 position;
XMFLOAT3 up;
XMFLOAT3 lookat;

void Camera::rotate(XMFLOAT3 vector, float theta) {
    XMStoreFloat4x4(&cameraMatrix, XMMatrixIdentity());

//set our view quaternion to our current camera's lookat position
XMVECTOR viewQuaternion = XMQuaternionIdentity();
viewQuaternion = XMVectorSet(lookat.x, lookat.y, lookat.z, 0.0f);

//set the rotation vector based on our parameter, i.e (1.0f, 0.0f, 0.0f)
//to rotate around the x axis
XMVECTOR rotationVector = XMVectorSet(vector.x, vector.y, vector.z, 0.0f);
//create a rotation quaternion to rotate around our vector, with a specified angle, theta
XMVECTOR rotationQuaternion = XMVectorSet(
XMVectorGetX(rotationVector) * sin(theta / 2),
XMVectorGetY(rotationVector) * sin(theta / 2),
XMVectorGetZ(rotationVector) * sin(theta / 2),
cos(theta / 2));

//get our rotation quaternion inverse
XMVECTOR rotationInverse = XMQuaternionInverse(rotationQuaternion);

//new view quaternion = [ newView = ROTATION * VIEW * INVERSE ROTATION ]
//multiply our rotation quaternion with our view quaternion
XMVECTOR newViewQuaternion = XMQuaternionMultiply(rotationQuaternion, viewQuaternion);

//multiply the result of our calculation above with the inverse rotation
//to get our new view values
newViewQuaternion = XMQuaternionMultiply(newViewQuaternion, rotationInverse);

//take the new lookat values from our newViewQuaternion and put them into the camera
lookat = XMFLOAT3(XMVectorGetX(newViewQuaternion), XMVectorGetY(newViewQuaternion), XMVectorGetZ(newViewQuaternion));

//build our camera matrix using XMMatrixLookAtLH
XMStoreFloat4x4(&cameraMatrix, XMMatrixLookAtLH(
    XMVectorSet(position.x, position.y, position.z, 0.0f),
    XMVectorSet(lookat.x, lookat.y, lookat.z, 0.0f),
    XMVectorSet(up.x, up.y, up.z, 0.0f)));
}

然后设置视图矩阵

//store our camera's matrix inside the view matrix
XMStoreFloat4x4(&_view, camera->getCameraMatrix() );

-

编辑:

我尝试了一种不使用四元数的替代解决方案,似乎我可以让相机绕自己的轴正确旋转,但相机的外观值现在永远不会改变,在我停止使用鼠标/键盘后,它会快照回到原来的位置。

void Camera::update(float delta) {
    XMStoreFloat4x4(&cameraMatrix, XMMatrixIdentity());

//do we have a rotation?
//this is set as we try to rotate, around a current axis such as
//(1.0f, 0.0f, 0.0f)
if (rotationVector.x != 0.0f || rotationVector.y != 0.0f || rotationVector.z != 0.0f) {

    //yes, we have an axis to rotate around

//create our axis vector to rotate around
    XMVECTOR axisVector = XMVectorSet(rotationVector.x, rotationVector.y, rotationVector.z, 0.0f);

//create our rotation matrix using XMMatrixRotationAxis, and rotate around this axis with a specified angle theta
    XMMATRIX rotationMatrix = XMMatrixRotationAxis(axisVector, 2.0 * delta);

//create our camera's view matrix
    XMMATRIX viewMatrix = XMMatrixLookAtLH(
        XMVectorSet(position.x, position.y, position.z, 0.0f),
        XMVectorSet(lookat.x, lookat.y, lookat.z, 0.0f),
        XMVectorSet(up.x, up.y, up.z, 0.0f));

//multiply our camera's view matrix by the rotation matrix
//make sure the rotation is on the right to ensure local axis rotation
    XMMATRIX finalCameraMatrix = viewMatrix * rotationMatrix;


/* this piece of code allows the camera to correctly rotate and it doesn't
snap back to its original position, as the lookat coordinates are being set
each time. However, this will make the camera rotate around the world axis
rather than the local axis. Which brings us to the same problem we had
with the quaternion rotation */
    //XMVECTOR look = XMVectorSet(lookat.x, lookat.y, lookat.z, 0.0);

    //XMVECTOR finalLook = XMVector3Transform(look, rotationMatrix);

    //lookat.x = XMVectorGetX(finalLook);
    //lookat.y = XMVectorGetY(finalLook);
    //lookat.z = XMVectorGetZ(finalLook);

//finally store the finalCameraMatrix into our camera matrix
    XMStoreFloat4x4(&cameraMatrix, finalCameraMatrix);
} else {

    //no, there is no rotation, don't apply the roation matrix

//no rotation, don't apply the rotation matrix
    XMStoreFloat4x4(&cameraMatrix, XMMatrixLookAtLH(
        XMVectorSet(position.x, position.y, position.z, 0.0f),
        XMVectorSet(lookat.x, lookat.y, lookat.z, 0.0f),
        XMVectorSet(up.x, up.y, up.z, 0.0f)));
}

这里可以看到一个例子:https://i.gyazo.com/f83204389551eff427446e06624b2cf9.mp4

我想我错过了将实际的lookat值设置为新的lookat值,但我不确定如何计算新值,或者从新的视图矩阵中提取它(我已经尝试过)

0 个答案:

没有答案