这个话题已经讨论过很多次了。关于互联网上OpenGL中矩阵的内存布局有很多信息。可悲的是,不同的来源经常相互矛盾。
我的问题归结为:
当我的矩阵
bx
,by
和bz
有三个基矢量时。如果我想用它们制作矩阵将它们插入到着色器中,它们如何在内存中布局?
让我们澄清基本向量的含义,因为我怀疑这也意味着不同的东西:
如果我有一个3D模型,那就是Z-up,我想沿着X轴将它平放在我的世界空间中,那么bz
就是[1 0 0]
。即当该顶点乘以具有[0 0 2]
作为Z轴基本向量的矩阵时,模型空间中的顶点[2 0 0]
将转换为bz
。
来到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]);
所以,为了获得最佳性能,我应该在顶点着色器中预先设置我的顶点(这样GPU可以使用点积等等):
attribute vec4 vertex;
uniform mat4 mvp;
void main()
{
gl_Position = vertex * mvp;
}
现在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 ]
或:
[
0 4 8 12,
1 5 9 13,
2 6 10 14,
3 7 11 15,
]
这意味着我必须将我的基本向量存储在这样的行中:
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
因此,对于我想要平放的3D模型的示例,它具有基本向量:
bx = [0 0 -1]
by = [0 1 0]
bz = [1 0 0]
上面的模型顶点[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]
正如所料!
恰恰相反:
这:Correct OpenGL matrix format? 因此问题以及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
对我来说,这两个来自Khronos的官方文件似乎互相矛盾。
有人可以向我解释一下吗?我弄错了吗?确实有一些错误的信息吗?
答案 0 :(得分:4)
常见问题解答是正确的,应该是:
<?xml version="1.0" encoding="utf-16"?>
<Root>
<NameOfMyRoot xmlns:ns="myNamespace">
<ns:SomeString></ns:SomeString>
</NameOfMyRoot>
</Root>
这是你的理由存在缺陷。
假设您的基矢量bx,by,bz是世界坐标中给出的模型基础,那么从模型空间顶点v到世界空间顶点Bv的变换由基矢量的线性组合给出:
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
它不是b与v的点积。而是它的矩阵乘法,其中B是上述形式。
采用顶点u和bx的点积将回答相反的问题:给定一个世界空间你沿着轴bx在模型空间中的坐标是什么?因此,乘以转置矩阵B*v = bx*v.x + by*v.y + bz*v.z
将为您提供从世界空间到模型空间的转换。