【问题标题】:Opengl - GLM::Ortho + GLM_COORDINATE_SYSTEM = weird?Opengl - GLM::Ortho + GLM_COORDINATE_SYSTEM = 奇怪?
【发布时间】:2018-05-31 02:40:24
【问题描述】:

虽然我是 opengl 的新手并且很少寻求帮助,但我认为需要对 Z 轴、深度测试和 GLM:ortho 进行一些澄清。 已经为此苦苦挣扎了一两个星期,一切从一开始就被“逆转”了。

所以我使用:

  • glDepthFunc(GL_LESS);
  • glDepthRange(0.0f, 1.0f);
  • glm::ortho(0.0f, 800, 0.0f, 800), 0.0f, 1.0f);
  • Z 轴为 Y / 800(高度),Y = 20 的对象在 Y = 10 的后面。

Okej,所以一切都应该加起来,小 Z 在前面,大在后面,但不是。一切都相反。

根据thread 和 glDepthFunc/glClearDepth 的默认值,当 MVP 提供给着色器时,一切都应该在左手坐标中。

因此,当我阅读链接线程时,我发现 glm::ortho 应该将右手坐标(因为显然这是每个人在示例中使用的)转换为左手坐标。听起来很棒,为什么它不起作用?

当您查看 GLM 库时,您会发现 glm::ortho、glm::orthoLH 和 glm::orthoRH 听起来很有趣。如果我使用 glm::orthoLH 一切都加起来并且工作完美,因为它将我所有的坐标转换为左手坐标。那么为什么 glm::ortho 不为我这样做呢?

在您编译 GLM 库时,显然有一个设置。 GLM_COORDINATE_SYSTEM 控制在调用 glm::ortho 时系统是否将 glm::orthoLH 或 glm::orthoRH 作为默认值。令我惊讶的是, glm::orthoLH 不是默认值。

如果你查看 GLM 的源代码,你会发现这些行,

#define GLM_LEFT_HANDED                         0x00000001      // For DirectX, Metal, Vulkan
#define GLM_RIGHT_HANDED                        0x00000002      // For OpenGL, default in GLM

#ifdef GLM_FORCE_LEFT_HANDED
#       define GLM_COORDINATE_SYSTEM GLM_LEFT_HANDED
#else
#       define GLM_COORDINATE_SYSTEM GLM_RIGHT_HANDED
#endif

OpenGL是右手的,不需要将正交转换为左手?

所以我的问题是,

  • 为什么 GLM 认为 OpenGL 是右撇子?
  • 在处理着色器时,OpenGL 是否真的希望 MVP 是右手的?

如果这没有任何意义,请纠正我。我也很困惑:)

【问题讨论】:

    标签: c++ opengl


    【解决方案1】:

    我认为您的主要困惑与这个问题有关:

    为什么 GLM 认为 OpenGL 是右撇子?

    OpenGL 既不是右手,也不是左手。 OpenGL 只是一个渲染 API,而不是一个坐标系。

    在典型的渲染管道中,您确实有很多不同的坐标系,例如:

    • 项目空间/模型空间
    • 世界空间
    • 眼睛空间/相机空间/视图空间
    • 剪辑空间
    • 标准化设备坐标
    • 窗台

    这些坐标系中的每一个都可以有自己的约定,包括自己的惯用手。

    具有固定功能管道和集成矩阵堆栈的旧版 OpenGL 考虑到了一些坐标约定(但它也没有完全强制您使用这些约定)。

    所以经典的 OpenGL 约定是:

    标准化的设备空间/窗口空间左手,x 指向右侧,y 向上,z 进入屏幕,眼睛空间右手,x 向右,y 向上,相机朝向 -z 方向。对象和世界空间通常也是右手的(因此视图变换只是旋转+平移,没有镜像)。

    左右手的翻转是在投影矩阵中完成的。传统 GL 没有其他约定是近和远剪辑平面位置总是定义为到观察方向的距离,所以glOrtho(..., 2,5) 实际上设置了一个将z_eye=-2 映射到@ 的转换987654323@ 和z_eye=-5z_ndc=1

    如果你看一下我刚刚写的映射,它应该可以解释这个问题:

    Okej,所以一切都应该加起来,小 Z 在前面,大 Z 在后面,但不是。一切都相反。

    如您所见,“小”z (-5) 在后面,“大”z (-2) 在前面,就像它应该在右手坐标系中一样。

    当您设置GLM_FORCE_LEFT_HANDED 时,glm 使用与旧版 GL 相同的约定。它将通过翻转投影矩阵中的 z 来建立一个右手视图空间(并假设所有后面的空间 NDC 和窗口空间都配置为左手)。

    如果您设置GLM_FORCE_LEFT_HANDED,它不会引入沿z 方向的镜像,但仍会将nearfar 视为与观察方向的距离,现在是+z。这将产生建立左手视图空间的结果(只要 NDC 和窗口空间也设置为左手)。

    在处理着色器时,OpenGL 是否真的希望 MVP 是右手的?

    这些都是约定俗成的。您必须以一种或另一种方式来决定它们,并且没有人比另一个人更好。只有当你有不同的部分或部分使用不同的约定时,这些东西才会变得有趣(和烦人),你必须非常小心地在正确的位置正确转换数据。

    【讨论】:

    • 感谢您的回答。您有什么资格成为传统 GL?我是否理解您的正确镜像 z 值在 GL 版本之间存在差异?
    • 我认为现代 GL 中不推荐使用的所有内容都是“遗留”,尤其是从核心配置文件中删除的所有内容。 “我是否理解你的正确镜像 z 值在 GL 版本之间存在差异?”不,现代 GL 不再有任何矩阵函数,处理这些空间完全取决于您(通过在顶点着色器中应用您喜欢的任何数学),因此不再有这样的约定。不过,如果经常使用额外的库作为替代,它们会带来自己的一套约定——在 glm 的情况下,默认情况下与旧版 GL 相同。
    • 疯狂,但现在更有意义了。非常感谢您的帮助。
    猜你喜欢
    • 2015-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-18
    相关资源
    最近更新 更多