弧球相机以90度方位角反转

时间:2016-10-22 18:24:57

标签: c++ opengl opengl-3 glm-math arcball

我正在尝试实施一个弧形风格的相机。我使用glm :: lookAt让相机指向目标,然后使用方位角/倾斜角度围绕球体表面移动它来旋转视图。

我遇到了一个问题,当方位角接近90度时,视图会颠倒翻转。

以下是相关代码:

  1. 获取投影并查看好消息。在主循环中运行

    void Visual::updateModelViewProjection()
    {
        model = glm::mat4();
        projection = glm::mat4();
        view = glm::mat4();
    
        projection = glm::perspective
            (
            (float)glm::radians(camera.Zoom),
            (float)width / height, // aspect ratio
            0.1f, // near clipping plane
            10000.0f // far clipping plane
            );
    
        view = glm::lookAt(camera.Position, camera.Target, camera.Up);
    }
    
  2. 鼠标移动事件,用于相机旋转

    void Visual::cursor_position_callback(GLFWwindow* window, double xpos, double ypos)
    {
        if (leftMousePressed)
        {
           ...
        }
    
        if (rightMousePressed)
        {
            GLfloat xoffset = (xpos - cursorPrevX) / 4.0;
            GLfloat yoffset = (cursorPrevY - ypos) / 4.0;
    
            camera.inclination += yoffset;
            camera.azimuth -= xoffset;
            if (camera.inclination > 89.0f)
                camera.inclination = 89.0f;
            if (camera.inclination < 1.0f)
                camera.inclination = 1.0f;
    
            if (camera.azimuth > 359.0f)
                camera.azimuth = 359.0f;
            if (camera.azimuth < 1.0f)
                camera.azimuth = 1.0f;
    
            float radius = glm::distance(camera.Position, camera.Target);
            camera.Position[0] = camera.Target[0] + radius * cos(glm::radians(camera.azimuth)) * sin(glm::radians(camera.inclination));
            camera.Position[1] = camera.Target[1] + radius * sin(glm::radians(camera.azimuth)) * sin(glm::radians(camera.inclination));
            camera.Position[2] = camera.Target[2] + radius * cos(glm::radians(camera.inclination));
    
            camera.updateCameraVectors();
        }
    
        cursorPrevX = xpos;
        cursorPrevY = ypos;
    }
    
  3. 计算相机方向矢量

    void updateCameraVectors()
    {
        Front = glm::normalize(Target-Position);
        Right = glm::rotate(glm::normalize(glm::cross(Front, {0.0, 1.0, 0.0})), glm::radians(90.0f), Front);
        Up = glm::normalize(glm::cross(Front, Right));
    }
    
  4. 我很确定这与我计算相机右侧矢量的方式有关,但我无法弄清楚如何补偿。

    有没有人遇到过这个?有什么建议?

1 个答案:

答案 0 :(得分:1)

使用lookAt旋转相机是一个常见的错误。你不应该。向后/向右/向上方向视图矩阵的列。如果您已经拥有它们,那么您甚至不需要lookAt,它会尝试重做您的一些计算。另一方面,lookAt并不能帮助您首先找到这些向量。

首先将视图矩阵构建为翻译和旋转的组合,然后从其列中提取这些向量:

void Visual::cursor_position_callback(GLFWwindow* window, double xpos, double ypos)
{
    ...
    if (rightMousePressed)
    {
        GLfloat xoffset = (xpos - cursorPrevX) / 4.0;
        GLfloat yoffset = (cursorPrevY - ypos) / 4.0;

        camera.inclination = std::clamp(camera.inclination + yoffset, -90.f, 90.f);
        camera.azimuth = fmodf(camera.azimuth + xoffset, 360.f);

        view = glm::mat4();
        view = glm::translate(view, glm::vec3(0.f, 0.f, camera.radius)); // add camera.radius to control the distance-from-target
        view = glm::rotate(view, glm::radians(camera.inclination + 90.f), glm::vec3(1.f,0.f,0.f));
        view = glm::rotate(view, glm::radians(camera.azimuth), glm::vec3(0.f,0.f,1.f));
        view = glm::translate(view, camera.Target);

        camera.Right = glm::column(view, 0);
        camera.Up = glm::column(view, 1);
        camera.Front = -glm::column(view, 2); // minus because OpenGL camera looks towards negative Z.
        camera.Position = glm::column(view, 3);

        view = glm::inverse(view);
    }
    ...
}

然后从updateModelViewProjectionupdateCameraVectors中删除计算视图和方向向量的代码。

免责声明:此代码未经测试。您可能需要在某处修改减号,操作顺序或约定可能不匹配(Z为up或Y为up等等)。