【问题标题】:OpenGL draw a rectangle filling windowOpenGL绘制一个矩形填充窗口
【发布时间】:2020-04-16 13:22:50
【问题描述】:

我正在尝试理解 OpenGL MVP 矩阵,作为练习,我想使用矩阵绘制一个填充我的窗口的矩形。我以为我会很容易地找到一个教程,但我发现的所有这些似乎都只是在他们的 MVP 矩阵设置中放置了随机值。

假设我的矩形有这些坐标:

GLfloat vertices[] = {
    -1.0f,  1.0f,  0.0f, // Top-left
     1.0f,  1.0f,  0.0f, // Top-right
     1.0f, -1.0f,  0.0f, // Bottom-right
    -1.0f, -1.0f,  0.0f, // Bottom-left
};

这是我的 2 个三角形:

GLuint elements[] = {
    0, 1, 2,
    2, 3, 0
};

如果我用身份 MVP 矩阵绘制矩形,它会按预期填充屏幕。现在我想使用平截头体。以下是它的设置:

float m_fov = 45.0f;
float m_width = 3840;
float m_height = 2160;
float m_zNear = 0.1f;
float m_zFar = 100.0f;

由此我可以计算窗口在 z-near 和 z-far 处的宽度/高度:

float zNearHeight = tan(m_fov) * m_zNear * 2;
float zNearWidth = zNearHeight * m_width / m_height;
float zFarHeight = tan(m_fov) * m_zFar * 2;
float zFarWidth = zFarHeight * m_width / m_height;

现在我可以创建视图和投影矩阵了:

glm::mat4 projectionMatrix = glm::perspective(glm::radians(m_fov), m_width / m_height, m_zNear, m_zFar);
glm::mat4 viewMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -m_zNear));

我现在希望这会使我的矩形填满窗口:

glm::mat4 identity = glm::mat4(1.0f);
glm::mat4 rectangleModelMatrix = glm::scale(identity, glm::vec3(zNearWidth, zNearHeight, 1));

但是这样做,我的矩形太大了。我错过了什么?


解决方案:正如@Rabbid76 指出的那样,问题在于我的 z-near 大小的计算,它必须是:

float m_zNearHeight = tan(glm::radians(m_fov) / 2.0f) * m_zNear * 2.0f;
float m_zNearWidth = m_zNearHeight * m_width / m_height;

另外,我现在需要在规范化视图空间 ([-0.5, 0.5]) 而不是设备空间 ([-1, 1]) 中指定我的对象坐标。因此我的顶点现在必须是:

GLfloat vertices[] = {
    -0.5f,  0.5f,  0.0f, // Top-left
     0.5f,  0.5f,  0.0f, // Top-right
     0.5f, -0.5f,  0.0f, // Bottom-right
    -0.5f, -0.5f,  0.0f, // Bottom-left
};

【问题讨论】:

    标签: c++ opengl projection glm-math frustum


    【解决方案1】:

    物体在平行于视图 xy 平面的平面上的投影高度为

    h' = h * tan(m_fov / 2) / -z
    

    其中h 是平面上物体的高度,-z 是深度,m_fov 是视野角度。

    在您的情况下,m_fov 是 45°,-z 是 -0.1 (-m_zNear),因此 tan(m_fov / 2) / z 是 ~4,142。
    由于四边形的高度为 2,因此四边形的投影高度约为 8,282。

    要创建一个完全适合视口的四边形,请使用 90° 的视野角和 1 的对象距离,因为tan(90° / 2) / 1 是 1。例如:

    float m_fov = 90.0f;
    glm::mat4 projectionMatrix = glm::perspective(glm::radians(m_fov), m_width / m_height, m_zNear, m_zFar);
    glm::mat4 viewMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -1.0f));
    

    如果tan(m_fov / 2) == -z,则底部为 -1 顶部为 1 的对象适合视口。
    由于除以z,视口上对象的投影尺寸随着到相机的距离线性减小。

    【讨论】:

    • 天哪,我只是忘记将角度除以 2 并将其转换为弧度...使用 float m_zNearHeight = (float) tan(m_fov * M_PI / 180.0f / 2.0f) * m_zNear * 2.0f;钉它。感谢您指出我的错误!仍然是最后一个问题:我仍然必须将我的矩形缩放 0.5(或者在 [-0.5 .. 0.5] 而不是 [-1.0 .. 1.0] 中创建我的顶点)。 [-1.0 .. 1.0] 不是OpenGL默认坐标范围吗?
    • @TimAutin 在您的代码中,您有一个比例 lm::scale(identity, glm::vec3(zNearWidth, zNearHeight, 1))
    • 是的,这是将我的矩形调整为我的 z-near 平面的大小。但我仍然需要将矩形缩放 0.5 以使其填充窗口,或者在我的顶点数组中放置 0.5 而不是每个 1.0
    • @TimAutin 但规模已磨损zNearHeight = tan(m_fov) * m_zNear * 2;。 - 有因子 2。tan(m_fov) * m_zNear * 2 缩放大小为 1 的对象,但从 -1 到 1 的对象大小为 2。
    • 我认为我的公式没有错:tan(m_fov/2) = 0.5 * zNearHeight / zNear,它给出了zNearHeight = tan(m_fov) * m_zNear * 2;
    猜你喜欢
    • 1970-01-01
    • 2019-10-29
    • 1970-01-01
    • 2011-01-16
    • 1970-01-01
    • 2012-07-23
    • 1970-01-01
    • 2011-04-21
    • 2012-11-12
    相关资源
    最近更新 更多