C++ OpenGL相机-四元数视图矩阵的行为不正确,并且间距太小

C++ OpenGL相机-四元数视图矩阵的行为不正确,并且间距太小,c++,opengl,camera,rotation,quaternions,C++,Opengl,Camera,Rotation,Quaternions,我正在使用相机的当前方向(四元数)及其当前位置为相机创建视图矩阵 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);

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

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;
}
这有一个问题,我不相信四元数到矩阵的计算给出了正确的答案。平移摄影机按预期工作,但旋转摄影机会导致不正确的行为

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

旋转在这种方法中发生

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;
}
仍然存在的问题是,视图矩阵旋转看起来像是旋转绘制的对象,而不像普通FPS摄影机那样环视四周

我已经上传了一段视频到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);
}
编辑4:

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

我不能让每个方向轴的点积都工作

// 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;

为了给你一个明确的答案,我想我们需要一段代码来显示你是如何向OpenGL提供
视图
矩阵和顶点的。然而,这种症状听起来非常典型,即矩阵顺序不正确

考虑一些变量:
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)并完全覆盖旧方向

您检查以确保pitchAccum保持在[-90,90]范围内,但您已经注释掉了将利用该事实的部分。我觉得这很奇怪。在您写回复之前,我已经取消了对这段代码的注释,并声明pitchAccum确实在[-90,90]范围内。可能您的broswer没有拾取它?提供了视图、投影和模型矩阵(因此不需要恒等矩阵),并在顶点着色器中相乘(转换)<代码>gl_位置=MVP*vec4(垂直模型空间,1)MVP统一设置如下
glm::mat4 MVP=g_activeCamera->getProjectionMatrix()*g_activeCamera->getViewMatrix()
glUniformMatrix4fv(MatrixID,1,GL_FALSE,&MVP[0][0])
@user1423893我可以看到
pitchAccum
将保持在您指定的范围内,但您实际上没有使用
pitchAccum
;所以这没关系。夹紧
pitchAccum
时,保持
pitchDegrees
不变。然后使用该值。所以,如果你在你的投球极限,你仍然会继续投球,即使
pitchAccum
没有变得越来越大/越来越小。你是绝对正确的。这是我的疏忽。谢谢:)
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);
}
    glm::mat4 translation;
translation = glm::translate(translation, position);

view = glm::gtx::quaternion::toMat4(orientation) * translation;
// 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;