3

我正在使用它的当前方向(四元数)和它的当前位置为我的相机创建视图矩阵。

void Camera::updateViewMatrix()
{
    view = glm::gtx::quaternion::toMat4(orientation);

    // Include rotation (Free Look Camera)
    view[3][0] = -glm::dot(glm::vec3(view[0][0], view[0][1], view[0][2]), position);
    view[3][1] = -glm::dot(glm::vec3(view[1][0], view[1][1], view[1][2]), position);
    view[3][2] = -glm::dot(glm::vec3(view[2][0], view[2][1], view[2][2]), position);

    // Ignore rotation (FPS Camera)
    //view[3][0] = -position.x;
    //view[3][1] = -position.y;
    //view[3][2] = -position.z;

    view[3][3] = 1.0f;
}

这有一个问题,我不相信矩阵计算的四元数给出了正确的答案。平移相机按预期工作,但旋转它会导致不正确的行为。

我正在使用当前鼠标位置和屏幕中心之间的差异旋转相机(每帧重置鼠标位置)

int xPos;
int yPos;
glfwGetMousePos(&xPos, &yPos);

int centreX = 800 / 2;
int centreY = 600 / 2;

rotate(xPos - centreX, yPos - centreY);

// Reset mouse position for next frame
glfwSetMousePos(800 / 2, 600 / 2);

旋转发生在这种方法中

void Camera::rotate(float yawDegrees, float pitchDegrees)
{
    // Apply rotation speed to the rotation
    yawDegrees *= lookSensitivity;
    pitchDegrees *= lookSensitivity;

    if (isLookInverted)
    {
        pitchDegrees = -pitchDegrees;
    }

    pitchAccum += pitchDegrees;

    // Stop the camera from looking any higher than 90 degrees
    if (pitchAccum > 90.0f)
    {
        //pitchDegrees = 90.0f - (pitchAccum - pitchDegrees);
        pitchAccum = 90.0f;
    }

    // Stop the camera from looking any lower than 90 degrees
    if (pitchAccum < -90.0f)
    {
        //pitchDegrees = -90.0f - (pitchAccum - pitchDegrees);
        pitchAccum = -90.0f;
    }

    yawAccum += yawDegrees;

    if (yawAccum > 360.0f)
    {
        yawAccum -= 360.0f;
    }

    if (yawAccum < -360.0f)
    {
        yawAccum += 360.0f;
    }

    float yaw = yawDegrees * DEG2RAD;
    float pitch = pitchDegrees * DEG2RAD;

    glm::quat rotation;

    // Rotate the camera about the world Y axis (if mouse has moved in any x direction)
    rotation = glm::gtx::quaternion::angleAxis(yaw, 0.0f, 1.0f, 0.0f);

    // Concatenate quaterions
    orientation = orientation * rotation;

    // Rotate the camera about the world X axis (if mouse has moved in any y direction)
    rotation = glm::gtx::quaternion::angleAxis(pitch, 1.0f, 0.0f, 0.0f);

    // Concatenate quaternions
    orientation = orientation * rotation;
}

我是否正确连接四元数以获得正确的方向?

音高累积还有一个问题,因为它将我的视野限制在 ±5 度而不是 ±90 度。这可能是什么原因?

编辑:

我已经解决了音高累积的问题,使其范围为 [-90, 90]。事实证明,glm 使用度数而不是向量来表示轴角,并且四元数串联的乘法顺序不正确。

// Rotate the camera about the world Y axis
// N.B. 'angleAxis' method takes angle in degrees (not in radians)
rotation = glm::gtx::quaternion::angleAxis(yawDegrees, 0.0f, 1.0f, 0.0f);

// Concatenate quaterions ('*' operator concatenates)
// C#: Quaternion.Concatenate(ref rotation, ref orientation)
orientation = orientation * rotation;

// Rotate the camera about the world X axis
rotation = glm::gtx::quaternion::angleAxis(pitchDegrees, 1.0f, 0.0f, 0.0f);

// Concatenate quaterions ('*' operator concatenates)
// C#: Quaternion.Concatenate(ref orientation, ref rotation)
orientation = rotation * orientation;

剩下的问题是视图矩阵旋转似乎旋转了绘制的对象,而不是像普通的 FPS 相机那样环顾四周。

我已将视频上传到 YouTube 以演示该问题。我四处移动鼠标以更改相机的方向,但三角形似乎在旋转。

演示相机方向问题的 YouTube 视频

编辑2:

void Camera::rotate(float yawDegrees, float pitchDegrees)
{
    // Apply rotation speed to the rotation
    yawDegrees *= lookSensitivity;
    pitchDegrees *= lookSensitivity;

    if (isLookInverted)
    {
        pitchDegrees = -pitchDegrees;
    }

    pitchAccum += pitchDegrees;

    // Stop the camera from looking any higher than 90 degrees
    if (pitchAccum > 90.0f)
    {
        pitchDegrees = 90.0f - (pitchAccum - pitchDegrees);
        pitchAccum = 90.0f;
    }
    // Stop the camera from looking any lower than 90 degrees
    else if (pitchAccum < -90.0f)
    {
        pitchDegrees = -90.0f - (pitchAccum - pitchDegrees);
        pitchAccum = -90.0f;
    }

    // 'pitchAccum' range is [-90, 90]
    //printf("pitchAccum %f \n", pitchAccum);

    yawAccum += yawDegrees;

    if (yawAccum > 360.0f)
    {
        yawAccum -= 360.0f;
    }
    else if (yawAccum < -360.0f)
    {
        yawAccum += 360.0f;
    }

    orientation = 
        glm::gtx::quaternion::angleAxis(pitchAccum, 1.0f, 0.0f, 0.0f) * 
        glm::gtx::quaternion::angleAxis(yawAccum, 0.0f, 1.0f, 0.0f);
}

编辑3:

以下乘法顺序允许相机围绕自己的轴旋转,但朝向错误的方向:

    glm::mat4 translation;
translation = glm::translate(translation, position);

view = glm::gtx::quaternion::toMat4(orientation) * translation;

编辑4:

以下将起作用(根据旋转后的位置应用平移矩阵)

// Rotation
view = glm::gtx::quaternion::toMat4(orientation); 

// Translation
glm::mat4 translation;
translation = glm::translate(translation, -position);

view *= translation;

我无法让每个方向轴的点积都起作用

// Rotation
view = glm::gtx::quaternion::toMat4(orientation); 

glm::vec3 p(
    glm::dot(glm::vec3(view[0][0], view[0][1], view[0][2]), position),
    glm::dot(glm::vec3(view[1][0], view[1][1], view[1][2]), position),
    glm::dot(glm::vec3(view[2][0], view[2][1], view[2][2]), position)
    );

// Translation
glm::mat4 translation;
translation = glm::translate(translation, -p);

view *= translation;
4

1 回答 1

4

为了给你一个明确的答案,我认为我们需要代码来显示你如何实际向viewOpenGL 提供矩阵和顶点。然而,这个症状听起来很典型的矩阵顺序不正确。

考虑一些变量:
V表示相机当前方向的倒数(四元数)。
T表示保存相机位置的平移矩阵。这应该是一个单位矩阵,相机的位置在第四列(假设我们是右乘列向量)。
U代表方向变化的倒数。
p表示世界空间中的一个顶点。
注意:所有矩阵都是逆矩阵,因为变换将应用于顶点,而不是相机,但最终结果是相同的。

默认情况下,OpenGL 相机位于负 z 轴的原点。当视图没有改变时(U==I),那么顶点从世界坐标到相机坐标的转换应该是:p'=TVp。您首先定位相机(通过沿相反方向旋转世界),然后将相机平移到位置(通过沿相反方向移动世界)。

现在有几个地方可以放U。如果我们把U放在V的右边,那么我们就会得到第一人称视角的行为。当您向上移动鼠标时,当前视图中的任何内容都会围绕相机向下旋转。当您向右移动鼠标时,视野中的任何东西都会围绕相机向左旋转。

如果我们将U放在TV之间,那么相机相对于世界的轴而不是相机的轴转动。这是一种奇怪的行为。如果V碰巧把相机关到一边,然后上下移动鼠标将使世界看起来“滚动”而不是“俯仰”或“偏航”。

如果我们把U放在T的左边,那么相机会围绕世界的原点围绕世界的轴旋转。这可能更奇怪,因为它使相机飞越世界越快,相机离原点越远。然而,因为旋转是围绕原点进行的,如果相机恰好在看原点,那里的物体就会看起来像是在转动。这就是您所看到的,因为您使用点积来旋转相机的位置。

您检查以确保它pitchAccum保持在 [-90,90] 范围内,但是您已经注释掉了将利用该事实的部分。这对我来说似乎很奇怪。

你左乘俯仰但右乘偏航的方式使得你的四元数对你没有多大作用。他们只是拿着你的欧拉角。除非方向更改来自其他地方,否则您可以简单地说orientation = glm::gtx::quaternion::angleAxis(pitchAccum*DEG2RAD, 1.0f, 0.0f, 0.0f) * glm::gtx::quaternion::angleAxis(yawAccum*DEG2RAD, 0.0f, 1.0f, 0.0f);并完全覆盖旧的方向。

于 2012-08-28T16:14:21.717 回答