【问题标题】:Correct OpenGL matrix format?正确的OpenGL矩阵格式?
【发布时间】:2024-01-17 01:00:01
【问题描述】:

我的问题很简单:Projection 和 ModelView 矩阵的正确格式是什么?

有人告诉我,以下示例矩阵是转置的,并不是像 OpenGL 矩阵那样构建的。

ModelView Matrix
{(1, 0, 0, 0)
(0, 0.7071068, 0.7071068, 0)
(0, -0.7071068, 0.7071068, 0)
(0, -141.4214, -141.4214, 1)}

Projection Matrix
{(1.931371, 0, 0, 0)
(0, 2.414213, 0, 0)
(0, 0, -1.0002, -1)
(0, 0, -2.0002, 0)}

【问题讨论】:

    标签: math opengl matrix


    【解决方案1】:

    编辑:这个答案急需更新。也就是说,没有考虑着色器。

    正如@gman 在 cmets 中指出的那样,是使用行优先还是列优先取决于您的数学运算方式。只要它们与您的坐标系和操作顺序相匹配,您就可以选择一个或另一个(或者甚至在不同的时间,如果您不认为这会造成混淆)。

    我将此答案保留为社区 wiki,以防有人有时间并愿意更新它。


    OpenGL 将矩阵指定为按列优先顺序列出的一维数组,即元素的顺序如下:

    m0 m4 m8  m12
    m1 m5 m9  m13
    m2 m6 m10 m14
    m3 m7 m11 m15
    

    因此,如果您以这种方式初始化数组,在 C 或几乎任何其他语言中,生成的矩阵看起来需要转置,因为 C 代码首先从左到右读取,然后从上到下读取(在换句话说,就像它是按行优先的顺序一样):

    int mat[16] = {
        0, 1, 2, 3,
        4, 5, 6, 7,
        8, 9, 10, 11,
        12, 13, 14, 15,
    }
    

    顺便说一句,OpenGL 有glLoadTransposeMatrixglMultTransposeMatrix,您可以使用它们来代替glLoadMatrix 和glMultMatrix,所以这应该不是问题。

    【讨论】:

    • 那么我如何判断我的问题中的矩阵是按列优先还是按行优先?
    • 模型-视图矩阵的最后一行有非零元素,而最后一列是 (0, 0, 0, 1)。这意味着它是按行优先顺序排列的。 (根据songho.ca/opengl/gl_transform.html#modelview
    • 同时,将投影矩阵与此链接中的投影矩阵进行对比 - songho.ca/opengl/gl_projectionmatrix.html - 似乎它是按列优先顺序排列的。不过请注意,我并没有真正考虑过这一点。
    • 这个答案不正确。 OpenGL 绝对支持行优先和列优先顺序。如果您使用的是 glUniformMatrix4fv,则如果您使用的是行优先,则第三个参数为 true,如果您使用的是列优先,则为 false。实际上,大多数使用 C 风格的数组和语法的编程语言都会以行为主,这样更方便。
    • @TalLiron 这不是我说的,在大多数编程语言中,以行优先形式初始化矩阵更容易吗?换位来自您在文本编辑器中编写的方式与您按照通常的数学约定编写的方式不同。它与 OpenGL 如何处理矩阵并没有真正的关系。
    【解决方案2】:

    您可以使用任何您喜欢的符号,只要您与矩阵运算的顺序一致。引用https://www.opengl.org/archives/resources/faq/technical/transformations.htm:

    9.005 OpenGL 矩阵是列优先还是行优先?

    出于编程目的,OpenGL 矩阵是 16 值数组 基向量在内存中连续布局。译文 组件占据 16 元素的第 13、14 和 15 个元素 矩阵,其中索引从 1 到 16 编号,如 OpenGL 2.1 规范的第 2.11.2 节。

    列优先与行优先纯粹是一种符号约定。笔记 与列主矩阵后乘产生相同的结果 结果作为与行主矩阵的预乘。 OpenGL 规范和 OpenGL 参考手册都使用 column-major 符号。您可以使用任何符号,只要明确说明即可。

    即在着色器中,您可以将变换矩阵作为按 columns 排序的浮点数组加载到统一中并 预乘 顶点来变换它:

    gl_Position = Proj * View * Model * vPosition;
    

    或加载与按rowspost-multiply排序的浮点数组相同的矩阵以达到相同的效果:

    gl_Position = vPosition * Model * View * Proj;
    

    通过转置矩阵,您可以有效地将其转换为以相反的符号存储,这就是为什么 OpenGL 可以在输入矩阵时选择转置矩阵。

    【讨论】:

    • 这向后看。第一阶乘法用于列优先矩阵,第二阶用于行优先矩阵。
    • 如果有人对上面的评论感到困惑(“这看起来向后看”),帖子已经被编辑以反映该评论。只是说以防不明显,因为这个****已经足够混乱了。 :)