opengl相机缩放到光标,避免> 90deg fov

时间:2016-11-05 17:40:44

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

我试图为我的opengl相机设置谷歌地图样式缩放到光标控制。我使用了类似于建议here的方法。基本上,我得到光标的位置,并使用一些三角函数计算我在该深度的透视图的宽度/高度。然后我改变视野,并计算我需要翻译的多少,以便将光标下的点保持在屏幕上相同的明显位置。那部分效果很好。

问题是我想将fov限制在90度以下。当它结束> 90时,我将其切成两半,然后将所有内容从相机转换出来,以便得到的场景看起来与较大的fov相同。找到必要翻译的等式并不起作用,这很奇怪,因为它来自非常简单的代数。我无法找到我的错误。这是相关的代码。

void Visual::scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
    glm::mat4 modelview = view*model;
    glm::vec4 viewport = { 0.0, 0.0, width, height };

    float winX = cursorPrevX;
    float winY = viewport[3] - cursorPrevY;
    float winZ;

    glReadPixels(winX, winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);
    glm::vec3 screenCoords = { winX, winY, winZ };

    glm::vec3 cursorPosition = glm::unProject(screenCoords, modelview, projection, viewport);

    if (isinf(cursorPosition[2]) || isnan(cursorPosition[2])) {
        cursorPosition[2] = 0.0;
    }

    float zoomFactor = 1.1;
    // = zooming in 
    if (yoffset > 0.0)
        zoomFactor = 1/1.1;

    //the width and height of the perspective view, at the depth of the cursor position 
    glm::vec2 fovXY = camera.getFovXY(cursorPosition[2] - zTranslate, width / height);
    camera.setZoomFromFov(fovXY.y * zoomFactor, cursorPosition[2] - zTranslate);

    //don't want fov to be greater than 90, so cut it in half and move the world farther away from the camera to compensate
    //not working...
    if (camera.Zoom > 90.0 && zTranslate*2 > MAX_DEPTH) {
        float prevZoom = camera.Zoom;
        camera.Zoom *= .5;

        //need increased distance between camera and world origin, so that view does not appear to change when fov is reduced
        zTranslate = cursorPosition[2] - tan(glm::radians(prevZoom)) / tan(glm::radians(camera.Zoom) * (cursorPosition[2] - zTranslate));
    }
    else if (camera.Zoom > 90.0) {
        camera.Zoom = 90.0;
    }

    glm::vec2 newFovXY = camera.getFovXY(cursorPosition[2] - zTranslate, width / height);

    //translate so that position under the cursor does not appear to move.
    xTranslate += (newFovXY.x - fovXY.x) * (winX / width - .5);
    yTranslate += (newFovXY.y - fovXY.y) * (winY / height - .5);

    updateView = true;
}

我的视图矩阵的定义。称为主循环的迭代。

void Visual::setView() {
    view = glm::mat4();

    view = glm::translate(view, { xTranslate,yTranslate,zTranslate });

    view = glm::rotate(view, glm::radians(camera.inclination), glm::vec3(1.f, 0.f, 0.f));
    view = glm::rotate(view, glm::radians(camera.azimuth), glm::vec3(0.f, 0.f, 1.f));

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

    updateView = false;
}

视野辅助功能。

glm::vec2 getFovXY(float depth, float aspectRatio) {
    float fovY = tan(glm::radians(Zoom / 2)) * depth;
    float fovX = fovY * aspectRatio;

    return glm::vec2{ 2*fovX , 2*fovY };
}

//you have a desired fov, and you want to set the zoom to achieve that.
//factor of 1/2 inside the atan because we actually need the half-fov. Keep full-fov as input for consistency 
void setZoomFromFov(float fovY, float depth) {
    Zoom = glm::degrees(2 * atan(fovY / (2 * depth)));
}

我可以从图here中找到我使用的等式。由于我希望在角度改变之前和之后具有相同的视野尺寸,我从

开始
fovY = tan(theta1) * d1 = tan(theta2) * d2
d2 = (tan(theta1) / tan(theta2)) * d1

d1 = distance between camera and cursor position, before fov change = cursorPosition[2] - zTranslate
d2 = distance after
theta1 = fov angle before
theta2 = fov angle after = theta1 * .5

感谢帮助。

0 个答案:

没有答案