Arcball摄像机以90度方位角反转 [英] Arcball camera inverting at 90 deg azimuth

查看:164
本文介绍了Arcball摄像机以90度方位角反转的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现一个Arcball风格的相机.我使用glm :: lookAt来使相机对准目标,然后使用方位角/倾斜角将其围绕球体表面移动以旋转视图.

I'm attempting to implement an arcball style camera. I use glm::lookAt to keep the camera pointed at a target, and then move it around the surface of a sphere using azimuth/inclination angles to rotate the view.

我遇到一个问题,当方位角接近90度时,视图会上下颠倒.

I'm running into an issue where the view gets flipped upside down when the azimuth approaches 90 degrees.

以下是相关代码:

  1. 获取投影并查看矩阵.在主循环中运行

  1. Get projection and view martrices. Runs in the main loop

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);
}

  • 鼠标移动事件,用于相机旋转

  • Mouse move event, for camera rotation

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

  • 计算相机方向矢量

  • Calculate camera orientation vectors

    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));
    }
    

  • 我很确定这与我计算相机正确向量的方式有关,但是我不知道该如何补偿.

    I'm pretty sure it's related to the way I calculate my camera's right vector, but I cannot figure out how to compensate.

    以前有人遇到过吗?有什么建议?

    Has anyone run into this before? Any suggestions?

    推荐答案

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

    It's a common mistake to use lookAt for rotating the camera. You should not. The backward/right/up directions are the columns of your view matrix. If you already have them then you don't even need lookAt, which tries to redo some of your calculations. On the other hand, lookAt doesn't help you in finding those vectors in the first place.

    相反,首先将视图矩阵构建为平移和旋转的组合,然后从其列中提取这些矢量:

    Instead build the view matrix first as a composition of translations and rotations, and then extract those vectors from its columns:

    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中删除计算视图和方向矢量的代码.

    Then remove the code that calculates view and the direction vectors from updateModelViewProjection and updateCameraVectors.

    免责声明:此代码未经测试.您可能需要在某处固定减号,操作顺序,或者约定可能不匹配(Z向上或Y向上等等).

    Disclaimer: this code is untested. You might need to fix a minus sign somewhere, order of operations, or the conventions might mismatch (Z is up or Y is up, etc...).

    这篇关于Arcball摄像机以90度方位角反转的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆