鉴于此顶点着色器:
attribute vec3 vertex;
uniform mat4 mvp;
void main() {
gl_Position = mvp * vec4(vertex, 1.0);
}
这个片段着色器:
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
当mvp
矩阵是标识符或模型矩阵是缩放,旋转或转换变换时,能够呈现下面的数据:
GLfloat values[] = {
-1.0, -1.0, +0.0,
+1.0, -1.0, +0.0,
+0.0, +1.0, +0.0,
};
为什么Qt' QMatrix4x4::lookAt
和QMatrix4x4::perspective
的以下用法会导致场景被渲染,好像没有对象在那里?
QMatrix4x4 model;
QMatrix4x4 view;
view.lookAt(
QVector3D(0.0, 0.0, 10.0), // Eye
QVector3D(0.0, 0.0, 0.0), // Focal Point
QVector3D(0.0, 1.0, 0.0)); // Up vector
QMatrix4x4 proj;
// Window size is fixed at 800.0 by 600.0
proj.perspective(45.0, 800.0 / 600.0, 1.0, 100.0);
QMatrix4x4 mvp = (model * view * proj);
我正在寻找的不仅仅是如何修复代码,还有将来我可以尝试调试这些东西。
只是在预感中我将mvp更改为p * v * m并解决了问题。如果你必须以相反的顺序进行乘法,为什么它是mvp?我知道矩阵乘法不是传递的。也就是说,如果A和B是矩阵,如果A和B不是I,则A * B!= B * A.
答案 0 :(得分:5)
它被称为MVP,因为......有人以这种方式命名。 ;)
但是,这是有道理的。它基本上按照它们应用的顺序列出转换。首先将模型矩阵应用于顶点,然后将View矩阵应用于其结果,然后将投影矩阵应用于两者的结果。或者在数学上,对于输入顶点vObj
,您可以写:
vWorld = M * vObj
vEye = V * vWorld
vClip = P * vEye
如果你用方程式代替,你得到:
vClip = P * vEye = P * (V * vWorld) = P * (V * (M * vObj))
矩阵乘法是关联的,因此可以重写为:
P * (V * (M * vObj)) = (P * V * M) * vObj
因此,组合矩阵计算为P * V * M
。
答案 1 :(得分:1)
Reto Koradi是对的。这不是因为内存布局或其他原因,而是因为OpenGL使用列向量 - 具有四行和一列或4x1矩阵的矩阵。转换是Matrix4x4 * Vector,以满足矩阵乘法的标准(结果再次是列向量)。
另一种方法是将向量定义为行(1x4矩阵),然后所有变换都是vWorld = vObj * M
等,以满足矩阵乘法的标准,从而得到行向量。突然之间,最后一行被重写为vClip = vObj * M * V * P
。
矩阵乘法总是相同的,你不需要关心矩阵如何存储在内存中(好吧,除非它是线性数组,你需要在行/列处寻址元素),但是变换矩阵根据定义而有所不同矢量。
在OpenGL中,总是从右到左组成变换。请记住,最左边的矩阵最后应用。
由于某种原因(历史记录?),向量通常被认为是列向量,变换矩阵从右到左应用,但如下面的注释中所述,可以在GL着色语言(GLSL)中使用这两种方法。 / p>
答案 2 :(得分:0)
它与矩阵的维数和数学符号有关。矩阵的尺寸定义为行x列。所以1x3矩阵是M = [a b c]。然后4x4矩阵如预期的那样。
只有当B = C(行到列并对结果求和)时,才能将两个维度AxB和CxD的矩阵相乘。
具有XYZW坐标的N个顶点的列表可以定义为矩阵Nx4或4xN的大小,但如果顶点块位于矩阵之后,则只有4xN与乘法运算符的定义一起使用:
V' (4×N)= M(4×4)×V(4×N)
因此顶点被视为列向量,以使此表示法有效。