在 OpenGL 中使用左上原点

Use top-left origin in OpenGL

我正在尝试设置坐标系,使 y 轴指向屏幕下方。

// Determine view-projection matrix
glm::mat4 projection = glm::ortho(
    -3.0f,    // left
    3.0f,     // right
    3.0f,     // bottom
    -3.0f);   // top

// Right handed rule:
// x points right
// y points down
// z points into the screen
glm::mat4 view = glm::lookAt(
    glm::vec3(0, 0, -1),    // camera position
    glm::vec3(0, 0, 0),     // look at
    glm::vec3(0, -1, 0)     // up vector
);

glm::mat4 viewProjMatrix = projection * view;

但是,当我尝试渲染 2 个对象时:

A at (0, 0)
B at (1, 1)

A​​出现在屏幕中央,B出现在右上角。我希望它出现在右下角。

我在这里错过了什么?

tl;博士

我的相机定位正确(从某种意义上说),但我在调用 glOrtho 时翻转了 y 轴。

让我们想象一下

想象一个右手坐标系,例如 OpenGL 按照惯例使用的坐标系:

  • x轴指向右边
  • y轴指向上方
  • z轴指向屏幕外

如果我的物体被放置在这个世界上并且我们从前面观察它们,我们会看到:

    B
A

这和我看到的一样,但我们不是从正面看。正如@Scheff 在评论中指出的那样,我对 glm::lookat 的调用是将我的相机倒置并将其定位 "behind" 屏幕。

现在,如果您想象自己在显示器后面做倒立,A 和 B 现在看起来像这样:

等等,但这不是我想要的吗 - 右下角的 B?

是的,但除了我的相机位置奇怪之外,我的 y 轴还因调用 glm::ortho 而翻转。通常 bottom 的值应小于 top 的值(如 this example)。

因此再次产生:

    B
A

因此,一种解决方案是交换 glOrtho 中的 topbottom 参数:

glm::mat4 view = glm::lookAt(
    glm::vec3(0, 0, -1),    // camera position
    glm::vec3(0, 0, 0),     // look at
    glm::vec3(0, -1, 0)     // up vector
);
glm::mat4 projection = glm::ortho(
    -3.0f,      // left
    3.0f,       // right
    -3.0f,      // bottom (less than top -> y-axis is not inverted!)
    3.0f);      // top

如何翻转y轴"correctly"

上面的解决方案有效,但还有一个更简单的解决方案 - 或者至少更易于可视化!这只是将相机定位在场景前面并使用 glOrtho 翻转 y 轴(通过保持 bottom 大于 top):

glm::mat4 view = glm::lookAt(
    glm::vec3(0, 0, 1),     // camera position
    glm::vec3(0, 0, 0),     // look at
    glm::vec3(0, 1, 0)      // up vector
);
glm::mat4 projection = glm::ortho(
    -3.0f,      // left
    3.0f,       // right
    3.0f,       // bottom (greater than top -> y-axis is inverted!)
    -3.0f);     // top

潜在问题

纹理方向

翻转 y 轴可能会导致纹理上下颠倒,这可以通过交换顶部和底部纹理坐标来解决。

背面剔除

如果启用 face culling,从不同角度查看场景可能会导致面孔被剔除。这可以通过更改顶点的缠绕顺序或通过更改 哪些 个面被剔除来解决。