OpenGL:基本向量如何在内存中布局

jsf*_*jsf 2 opengl matrix

这个话题已经讨论过很多次了。网上有很多关于OpenGL中矩阵内存布局的信息。可悲的是,不同的来源经常相互矛盾。

我的问题归结为:

当我有我的矩阵的三个基向量bx,bybz. 如果我想用它们制作一个矩阵以将它们插入着色器,它们在内存中的布局如何?

让我们澄清一下我所说的基向量是什么意思,因为我怀疑这也可能意味着不同的东西:

当我有一个 3D 模型时,它是 Z-up 并且我想将它沿 X 轴平放在我的世界空间中,然后bz[1 0 0]. 即[0 0 2]模型空间中的顶点将被转换为[2 0 0]当该顶点乘以我的矩阵时,该矩阵bz作为 Z 轴的基向量。

来到 OpenGL 矩阵内存布局:

根据 GLSL 规范(GLSL Spec p.110)它说:

vec3 v, u;
mat3 m;
u = v * m;

is equivalent to

u.x = dot(v, m[0]); // m[0] is the left column of m
u.y = dot(v, m[1]); // dot(a,b) is the inner (dot) product of a and b
u.z = dot(v, m[2]);
Run Code Online (Sandbox Code Playgroud)

因此,为了获得最佳性能,我应该在顶点着色器中预乘我的顶点(这样 GPU 可以使用点积等):

attribute vec4 vertex;
uniform mat4 mvp;
void main()
{
    gl_Position = vertex * mvp;
}
Run Code Online (Sandbox Code Playgroud)

现在 OpenGL 被称为列优先GLSL Spec p 101)。即列在内存中连续排列:

[ column 0 | column 1 | column 2  | column 3    ]
[ 0 1 2 3  | 4 5 6 7  | 8 9 10 11 | 12 13 14 15 ]
Run Code Online (Sandbox Code Playgroud)

或者:

[
    0  4  8 12,
    1  5  9 13,
    2  6 10 14,
    3  7 11 15,
]
Run Code Online (Sandbox Code Playgroud)

这意味着我必须将我的基本向量存储在这样的行中:

bx.x bx.y bx.z 0
by.x by.y by.z 0
bz.x bz.y bz.z 0
0    0    0    1
Run Code Online (Sandbox Code Playgroud)

因此,对于我想要平放的 3D 模型示例,它具有基本向量:

bx = [0 0 -1]
by = [0 1  0]
bz = [1 0  0]
Run Code Online (Sandbox Code Playgroud)

[0 0 2]上面的模型顶点将像顶点着色器中的 dis 一样转换:

// m[0] is [ 0 0 1 0]
// m[1] is [ 0 1 0 0]
// m[2] is [-1 0 0 0]
// v    is [ 0 0 2 1]
u.x = dot([ 0 0 2 1], [ 0 0 1 0]);
u.y = dot([ 0 0 2 1], [ 0 1 0 0]);
u.z = dot([ 0 0 2 1], [-1 0 0 0]);
// u    is [ 2 0 0]
Run Code Online (Sandbox Code Playgroud)

正如预期的那样!

相反:

这个:正确的OpenGL矩阵格式? SO 问题,因此OpenGL Faq指出:

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

这表示我的基本向量应该按这样的列排列:

bx.x by.x bz.x 0
bx.y by.y bz.y 0
bx.z by.z bz.z 0
0    0    0    1
Run Code Online (Sandbox Code Playgroud)

对我来说,这两个都是 Khronos 官方文档的来源似乎相互矛盾。

有人可以向我解释一下吗?我做错了吗?真的有什么错误的信息吗?

ybu*_*ill 5

FAQ是正确的,应该是:

bx.x by.x bz.x 0
bx.y by.y bz.y 0
bx.z by.z bz.z 0
0    0    0    1
Run Code Online (Sandbox Code Playgroud)

这是你的推理有缺陷。

假设您的基向量 bx, by, bz 是世界坐标中给出的模型基,那么从模型空间顶点 v 到世界空间顶点 Bv 的变换由基向量的线性组合给出:

B*v = bx*v.x + by*v.y + bz*v.z
Run Code Online (Sandbox Code Playgroud)

它不是 b 与 v 的点积。而是矩阵乘法,其中 B 具有上述形式。

取顶点 u 与 bx 的点积将回答相反的问题:给定一个世界空间 u,它在模型空间中沿轴 bx 的坐标是什么?因此,乘以转置矩阵transpose(B)将为您提供从世界空间到模型空间的转换。

  • @jsf:然后你误解了你读到的内容。GPU 可以像左乘一样快速地进行右乘。停止过早地优化东西。 (2认同)