17

假设我有一个蓝色的 3D 框(顶部为红色)。

  1. 现在我调用 glScalef(1, 10, 1)。
  2. 然后我调用 glRotatef(90, 0, 1, 0)。
  3. 然后我渲染立方体。

我期望看到红色的一面朝向屏幕(沿模型的 Y 轴)伸展。

但我看到的是:红色的一面朝向屏幕(如预期的那样)。但是拉伸发生在视图空间(而不是模型)的 Y 轴上。

我知道如果我沿 Z 轴设置比例,那么我会得到正确的结果。但我的困惑是,我认为在 Y 轴上放大,然后旋转盒子,会给我正确的结果。

我错过了什么?

4

2 回答 2

25

OpenGL 以所谓的column major顺序读取它的矩阵。结果是每个后续操作都是之前所有操作的预乘,而不是后乘。因此,对 OpenGL 操作(glScale、glTranslate、glRotate)的每个后续调用都是影响对象的第一件事,并且它的顺序与您编写它的顺序相反。

因此,您需要更改乘法顺序:

glRotatef(90, 0, 1, 0); // Notice how this is the first operation ...
// ... but will be applied after
glScalef(1, 10, 1); // This will be applied first, but is the last operation
// Zany, right?

说实话,当您编写程序并使用计算机必须以相反的顺序指定事物时,感觉不太直观。但是,被决定的图形之神就是他们希望 OpenGL 的矩阵堆栈的行为方式(以及 HLSL、GLSL 和其他系统:请参阅上面关于列优先排序的链接)。

于 2013-04-14T02:13:53.987 回答
0

如果您有一个表示 4x4 矩阵的数组,如下所示:

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

并将其加载到 OpenGL 矩阵中,OpenGL 将看到前 4 个浮点数作为矩阵的第一列,第二个 4 个浮点数作为第二列,第三个 4 个浮点数作为矩阵的第 3 列,依此类推。

因此,每 4 个浮点数,OpenGL 将其视为另一列。这称为列主要顺序。它将数据存储在列中。如果您必须转置一个以列为主的矩阵,它最终会成为一个以行为主的矩阵,反之亦然。

因为您有一个以列为主的矩阵,所以您还需要使用列向量,这意味着您的乘法顺序将为:M*v

为了向自己证明这一点,请使用一个带有 2x1 列向量的简单 2x2 矩阵,乘以M*v。设 K=transpose(M),r=行向量 (1x2)。

那么 M * v = r * K

最重要的是,一旦您在代码中使用列或行主要符号,您就必须坚持下去。

于 2014-12-17T00:56:55.333 回答