【问题标题】:Opengl Why premultiply matrices when rotating in global space?Opengl为什么在全局空间中旋转时预乘矩阵?
【发布时间】:2026-02-04 04:25:01
【问题描述】:

好的,我知道当我调用 glRotatef() 时它会这样做,

C = C * M

其中“C”是堆栈上的当前矩阵,“M”是由 glRotatef() 计算的矩阵。但是,这会导致对象围绕其局部轴旋转。 如果我想围绕其全局轴旋转对象,我必须这样做

 C = M * C

例如,如果我想绕全局 x 旋转,然后是全局 y,然后是全局 z。会是

C = Mz * My* Mx * C

我已经对其进行了测试,并且可以正常工作。我想知道为什么我们必须为全局旋转进行预乘,反之亦然。

在我的例子中,“C”是模型视图矩阵。 请注意,我不是在谈论矩阵与向量的预乘法。我知道所有列专业 - 行专业的东西。我想知道将转换前/后乘以另一个 matrix4x4 的后果。

【问题讨论】:

  • 这些只是说明你必须为全局旋转进行预乘,我想知道你为什么这样做而不是相反。我认为这与基础变换和空间的内部表示有关。 OGL 是如何知道“自从预乘以来我必须围绕全局轴旋转”
  • @Rabbid76:这是一道数学题,但它专门针对图形编程。

标签: c++ opengl matrix rotation


【解决方案1】:

在其核心,转换矩阵是将位置/方向从空间I 转换为空间O 的函数:输入到输出。因此,转换的行为很像函数组合。 f(g(X))g(f(X)) 是有区别的。

所以你从一个矩阵C开始,给定一个顶点Vi,它在空间I中,这将是真的:Vo = C * Vi,其中Vo是空间@987654330中的顶点@。

那么,让我们回到原来的例子:C = C * M。为了减少混淆(我需要谈谈原始的C 和输出),我将为新矩阵指定一个特定的名称:D = C * M

空间IC 的输入空间是一个特定的模型空间。您现在正在为此添加一个新的转换,它有自己的输入和输出空间。通过将它们相乘以形成一个单一的转换,您正在声明一些东西:

MoM 的输出空间,与CiC 的输入空间同一个空间。因此,我们现在处理三个空格:MiMo/CiCo

但是,D 是这些转换的组合。它从空间Mi 到空间Co;我们从未见过Mo/CiCD 的区别在于它们的输入空间。

事情是这样的:CoC 的输出空间?它有一个特殊的名称:世界空间

因此,DC 进入完全相同的世界空间。因此,右乘不会导致围绕世界空间旋转也就不足为奇了。

让我们来看看这个:E = M * C。在这里,我们有不同的情况。 EC 具有相同的输入空间(模型空间),但它现在具有不同的输出 空间。即E转换成的世界空间和C转换成的世界空间是不同的。

如果您想相对于世界空间旋转某些东西,这正是您想要的。您正在更改该对象的世界空间。

如果您更改模型空间以进行变换,则您正在相对于模型空间进行变换。如果您为变换更改世界空间,那么您正在相对于世界空间进行变换。

【讨论】:

  • 感谢您的回答,我觉得这更接近我的预期。有些事情我不明白。在D = C * M的情况下M的输入空间是什么,不就是模型空间吗?
  • @wandering-warrior:将空格的名称想象成变量的名称。它们对人们有用,但不会改变数学Co 是世界空间,因为我们它是世界空间并将其视为世界空间。但是C对“世界空间”一无所知;这只是从一个空间到另一个空间的转换。 M 也是如此。如果我们声明D 是从模型空间到世界空间的转换,那么我们同时声明MiD 的新模型空间。但这是一个概念选择,而不是 DM 的内在属性。
  • 那么这是否意味着我们直观地认为旋转矩阵具有相同的输入和输出空间?就像D = C * M M 获取模型空间中的顶点并返回模型空间中的顶点,而在D = M * C 中,它获取世界空间中的顶点并返回世界空间中修改后的顶点,从而围绕全局轴旋转?
  • @wandering-warrior:不,只有 identity 矩阵具有相同的输入和输出空间。每个矩阵都从其输入空间转换到其输出空间。我们所说的那些空间无关紧要。就像您命名变量无关紧要一样。如果你想打电话给Mo“mid-model-space”或“left-hip space”或“我刚刚编造的一些名字”,那很好。但是M 有一个输出空间。
  • 好的,我明白你想说的 xD 感谢您提供独特而广泛的答案。你能推荐一些书来润色这些数学概念吗?我已经阅读了一些图形,但它们并没有从数学 pov 中接近数学。我的意思是仅从图形的角度关注焦点。
【解决方案2】:

让我们从全局坐标系开始。你在第一个系统中有一个点V(x,y,z,w)

接下来,您在轴上进行旋转。旋转在矩阵M1 中定义。想想旋转轴,而不是点。同一点V 现在可以在这个新坐标系中表示为V'(x', y', z', w')。我们知道我们可以通过
V' = M1·V 使用 col-mayor 顺序并成为 V 4x1 矩阵。

接下来我们想要围绕可能的其他轴进行第二次旋转。 M2 是旋转矩阵。但是等等,我们是要相对旋转到第二个系统还是第一个系统?

V" = M2·V

V" = M2·V'

“不”,你说,“相对于第二个已经旋转的坐标系。”
好的。所以你有:

V" = M2·V'  = M2·(M1·V) = (M2·M1)·V  but **NOT=** (M1·M2)·V

关键是您将变换矩阵应用到以前的系统。您应用多个转换的顺序不是可交换的。例如,尝试“先平移再旋转”与“先旋转再平移”。

将点旋转角度alpha 或将轴旋转相反的-alpha 会产生相同的最终坐标。换句话说,您执行相同的矩阵运算。

然后用你的 C,M 命名法,让我们来看看 C·M 和 M·C 之间的区别
V1 = C·V0局部对象轴转换为全局轴
V2 = M·V0 在局部对象轴上旋转(变换)
V3 = M·V1 = M·C·V0转换为全局后旋转,这是在全局轴上
V4 = C·V2 = C·M·V0 在本地旋转后变换

注意到我为列长顺序编写了矩阵运算。

【讨论】:

    最近更新 更多