3D DirectX - 如何使用静态相机进行正确旋转?

时间:2014-03-06 13:27:56

标签: matrix rotation directx

对于学校项目,我们正在修改我们在早期课程中构建的游戏引擎,以支持Oculus Rift。然而,我们一直遇到的一个问题是,当我们移动鼠标时,世界似乎在旋转。在正常的第一人称场景中,人们可以毫无困难地使用相机移动,但在我们的引擎中,随机移动鼠标最终会使世界颠倒过来。用圆圈移动鼠标会再次拉直它。

我猜这是因为,由于相机是静止的,轴的位置永远不会改变,这反过来会导致不必要的旋转。有没有办法补偿这种旋转,例如通过确定一个任意轴并围绕它旋转?或者问题是完全不同的,我们是否完全在错误的区域寻找?

我们不允许在渲染器之外使用DirectX方法,因此我们自己进行所有矩阵乘法。

编辑:这是我们用来旋转相机的代码。它包含在两个类中。首先,Camera.cpp中的旋转代码(我们之前的作业要求我们处理相机中的输入):

void Camera::rotateByX(float angle)
{
    float rotX = -1.0f * angle / 1000.0f;
    xAngle = angle;
    //This is the calculation with the Rotion Matrix values of X
    matrixRotateX[5] = cos(rotX);
    matrixRotateX[6] = sin(rotX);
    matrixRotateX[9] = -sin(rotX);
    matrixRotateX[10] = cos(rotX);

    //The for loop to multiply the matrices
    float matrix[16];
    for(int i = 0; i < 16; ++i)
    {
        matrix[i] = matrixMultiply(changeMatrix, matrixRotateX)[i];
    }
    setChangeMatrix(matrix);
};

void Camera::rotateByY(float angle)
{   
    float rotY = -1.0f * angle / 1000.0f;
    //This is the calculation with the Rotion Matrix values of Y
    matrixRotateY[0] = cos(rotY);
    matrixRotateY[2] = -sin(rotY);
    matrixRotateY[8] = sin(rotY);
    matrixRotateY[10] = cos(rotY);

    //The for loop Multiply the matrices
    float matrix[16];
    for(int i = 0; i < 16; ++i)
    {
        matrix[i] = matrixMultiply(changeMatrix, matrixRotateY)[i];
    }
    setChangeMatrix(matrix);
};

矩阵乘法发生在这个怪物:

float* Camera::matrixMultiply(float matrix1[16], float matrix2[16])
{
    if(matrix1 != NULL && matrix2 != NULL)
    {
    float matrix[16];
    float coord = (matrix1[0] * matrix2[0] + matrix1[1] * matrix2[4] + matrix1[2] * matrix2[8] + matrix1[3] * matrix2[12]);
    matrix[0] = coord;
    coord = (matrix1[0] * matrix2[1] + matrix1[1] * matrix2[5] + matrix1[2] * matrix2[9] + matrix1[3] * matrix2[13]);
    matrix[1] = coord;
    coord = (matrix1[0] * matrix2[2] + matrix1[1] * matrix2[6] + matrix1[2] * matrix2[10] + matrix1[3] * matrix2[14]);
    matrix[2] = coord;
    coord = (matrix1[0] * matrix2[3] + matrix1[1] * matrix2[7] + matrix1[2] * matrix2[11] + matrix1[3] * matrix2[15]);
    matrix[3] = coord;
    coord = (matrix1[4] * matrix2[0] + matrix1[5] * matrix2[4] + matrix1[6] * matrix2[8] + matrix1[7] * matrix2[12]);
    matrix[4] = coord;
    coord = (matrix1[4] * matrix2[1] + matrix1[5] * matrix2[5] + matrix1[6] * matrix2[9] + matrix1[7] * matrix2[13]);
    matrix[5] = coord;
    coord = (matrix1[4] * matrix2[2] + matrix1[5] * matrix2[6] + matrix1[6] * matrix2[10] + matrix1[7] * matrix2[14]);
    matrix[6] = coord;
    coord = (matrix1[4] * matrix2[3] + matrix1[5] * matrix2[7] + matrix1[6] * matrix2[11] + matrix1[7] * matrix2[15]);
    matrix[7] = coord;
    coord = (matrix1[8] * matrix2[0] + matrix1[9] * matrix2[4] + matrix1[10] * matrix2[8] + matrix1[11] * matrix2[12]);
    matrix[8] = coord;
    coord = (matrix1[8] * matrix2[1] + matrix1[9] * matrix2[5] + matrix1[10] * matrix2[9] + matrix1[11] * matrix2[13]);
    matrix[9] = coord;
    coord = (matrix1[8] * matrix2[2] + matrix1[9] * matrix2[6] + matrix1[10] * matrix2[10] + matrix1[11] * matrix2[14]);
    matrix[10] = coord;
    coord = (matrix1[8] * matrix2[3] + matrix1[9] * matrix2[7] + matrix1[10] * matrix2[11] + matrix1[11] * matrix2[15]);
    matrix[11] = coord;
    coord = (matrix1[12] * matrix2[0] + matrix1[13] * matrix2[4] + matrix1[14] * matrix2[8] + matrix1[15] * matrix2[12]);
    matrix[12] = coord;
    coord = (matrix1[12] * matrix2[1] + matrix1[13] * matrix2[5] + matrix1[14] * matrix2[9] + matrix1[15] * matrix2[13]);
    matrix[13] = coord;
    coord = (matrix1[12] * matrix2[2] + matrix1[13] * matrix2[6] + matrix1[14] * matrix2[10] + matrix1[15] * matrix2[14]);
    matrix[14] = coord;
    coord = (matrix1[12] * matrix2[3] + matrix1[13] * matrix2[7] + matrix1[14] * matrix2[11] + matrix1[15] * matrix2[15]);
    matrix[15] = coord;

    return matrix; 
    }
    else
    {
        Logger::getInstance()->logWarning("Matrix is invalid.", __LINE__, "Camera");
    }
};

然后,在Scene.cpp文件中,通过以下方法调用这些乘法的结果:

void Scene::updateMatrices()
{
    //Change the matrices of all the Entities
    for (unsigned int i = 0; i < entities.size(); ++i)
    {
        float matrix[16];
        for (int j = 0; j < 16; ++j)
        {
                matrix[j] = entities[i]->matrixMultiply(camera->getChangeMatrix())[j];
        }
        entities[i]->setMatrix(matrix);
    }
    //Change the matrices of the Terrain
    float trMatrix[16];
    for (int i = 0; i < 16; ++i)
    {
            trMatrix[i] = terrain->matrixMultiply(camera->getChangeMatrix())[i];
    }
    terrain->setMatrix(trMatrix);
    //Change the matrices of the Skybox
    float skyMatrix[16];
    for (int i = 0; i < 12; ++i)
    {
        skyMatrix[i] = skybox->matrixMultiply(camera->getChangeMatrix())[i];
    }
    //The skybox does not move. Therefore we set its translation values to zero. 
    //This is necessary because the change matrix does contain trnaslation values.
    skyMatrix[12] = 0.0f;
    skyMatrix[13] = 0.0f;
    skyMatrix[14] = 0.0f;
    skyMatrix[15] = 1.0f;
    skybox->setMatrix(skyMatrix);
    //Resets the Change Matrix of the Camera
    camera->resetMatrix();
};

从这段代码可以清楚地看出,我们更像是英国的Top Gear:雄心勃勃但却很垃圾。我希望从这个混乱中可以学到任何东西。提前谢谢!

0 个答案:

没有答案