为什么我们使用4x4矩阵在3D模式下进行转换?


36

要在X方向上将向量平移10个单位,为什么我们必须使用矩阵?

在此处输入图片说明

我们可以在mat [0] [0]上加10,结果也一样。

Answers:


28

是的,如果需要翻译,可以添加一个向量。使用矩阵的原因归结为具有统一的方式来处理不同的组合变换。

例如,旋转通常是使用矩阵完成的(检查@MickLH注释以了解其他处理旋转的方式),因此,为了以统一的方式处理多个变换(旋转/平移/缩放/投影等),您需要将它们编码为矩阵。

好吧,从技术上来讲;转换将一个点/向量映射到另一个点/向量。

p` = T(p); 

其中p`是变换点,T(p)是变换函数。

假设我们不使用矩阵,则需要这样做以组合多个转换:

p1 = T(p);

p final = M(p1);

矩阵不仅可以将多种类型的变换组合到单个矩阵中(例如,仿射,线性,射影)。

使用矩阵使我们有机会组合转换链,然后将它们成批相乘。通常通过GPU,这可以为我们节省大量的周期(感谢@ChristianRau指出了这一点)。

T 最终 = T * R * P; //翻译旋转项目

p final = T final * p;

还要指出,GPU甚至某些CPU已针对矢量操作进行了优化。设计上使用SIMD的CPU和GPU是数据驱动的并行处理器,因此使用矩阵与硬件加速非常匹配(实际上,GPU被设计为适合矩阵/矢量运算)。


是的,我知道矩阵对于旋转很有用。但是每个教程都指导我使用矩阵来进行这种简单的计算:D
ngoaho91 2014年

1
说旋转只能“用矩阵完成”是不正确的,在我的头顶上,四元数和三角函数也可以正常工作
MickLH 2014年

17
不仅如此,一旦您将旋转和平移都作为4x4矩阵使用,就可以将它们相乘并将转换合并到一个矩阵中,而无需使用不同的构造通过数千个不同的转换来转换每个顶点。4x4矩阵对于单次平移或单次旋转是过大的事实,因为通常不仅仅通过单次平移或单次旋转来变换顶点,这一事实的重要性超过了事实。
克里斯说恢复莫妮卡2014年

1
@ concept3d是的,我知道,答案很好。但是,从统一使用矩阵的方式中获得的更大好处不仅是均匀性,而且是单个操作中整个变换链的表示。尽管可能暗示了这一点,但我发现它不清楚且重要,足以明确提及它。但是无论如何,答案还是不错的,这不是批评。
克里斯说恢复莫妮卡(Monica)2014年

1
是的,trig计算了旋转矩阵,但是矢量数学实际上使用注入了trig的数据集“旋转”了这些点。当我说三角函数时,我的意思是直接使用它而不是通过矩阵来生成一些简单的东西。
MickLH 2014年

6

如果您要做的只是沿单个轴移动而从不应用任何其他变换,那么您的建议就可以了。

使用矩阵的真正力量在于,您可以轻松地将一系列复杂的操作连接在一起,并将相同的一系列操作应用于多个对象。

大多数情况不是那么简单,如果您首先旋转对象,并想要沿其局部轴而不是世界轴进行变换,您会发现您不能简单地将10加到一个数字上并使其正确计算。


5

为了简洁地回答“为什么”问题,这是因为4x4矩阵可以一次描述旋转,平移和缩放操作。能够以一致的方式描述其中任何一个,可以简化很多事情。

可以使用不同的数学运算更简单地表示不同类型的转换。您已经注意到,翻译只需添加即可完成。通过乘以标量进行均匀缩放。但是精心制作的4x4矩阵可以执行任何操作。因此,始终如一地使用4x4会使代码和接口更加简单。您在理解这些4x4的过程中付出了一些复杂性,但是随之而来的是很多事情变得更加容易和快捷。


2
这应该是选定的答案。
工程师

4

使用4x4矩阵的原因是运算是线性变换。这是齐次坐标的一个例子。在2d情况下(使用3x3矩阵)可以完成相同的操作。使用齐次坐标的原因是,可以使用一次操作完成所有3种几何变形。否则,需要进行3x3矩阵乘法和3x3矩阵加法(用于转换)。来自cegprakash的此链接非常有用。


2
您应该详细说明。简洁的解释比仅链接至维基百科更好。
塞斯·巴丁

3

翻译不能用3D矩阵表示

一个简单的论点是翻译可以采用原点向量:

0
0
0

远离原点,对x = 1

1
0
0

但这将需要一个矩阵,使得:

| a b c |   |0|   |1|
| d e f | * |0| = |0|
| g h i |   |0|   |0|

但这是不可能的。

另一个论点是奇异值分解定理,它说每个矩阵都可以由两个旋转和一个缩放操作组成。那里没有翻译。

为什么可以使用矩阵?

许多建模对象(例如汽车底盘)或建模对象的一部分(例如汽车轮胎,驱动轮)都是实体:顶点之间的距离永远不变。

我们要对其进行的唯一转换是旋转和平移。

矩阵乘法可以编码旋转和平移。

旋转矩阵具有明确的公式,例如:角度的2D旋转矩阵a的形式为:

cos(a) -sin(a)
sin(a)  cos(a)

对于3D有类似的公式,但请注意3D旋转需要3个参数,而不仅仅是1个

翻译不太琐碎,将在后面讨论。这就是我们需要4D矩阵的原因。

为什么使用矩阵很酷?

因为可以通过矩阵乘法来预先计算多个矩阵的组成。

例如,如果我们要v使用matrix 转换汽车底盘的一千个向量,T然后使用matrix旋转R,而不是执行以下操作:

v2 = T * v

然后:

v3 = R * v2

对于每个向量,我们可以预先计算:

RT = R * T

然后为每个顶点做一个乘法:

v3 = RT * v

甚至更好:如果我们想要相对于汽车放置轮胎和驱动轮的顶点,我们只需将先前的矩阵乘以RT相对于汽车本身的矩阵即可。

这自然会导致维护一堆矩阵:

  • 计算底盘矩阵
  • 乘以轮胎矩阵(推)
  • 去除轮胎基料(爆裂声)
  • 通过驱动轮矩阵相乘(推)
  • ...

如何添加一维解决问题

让我们考虑一下从1D到2D的情况,这种情况更易于可视化。

一维矩阵只是一个数字,正如我们在3D中所见,它不能转换,只能缩放。

但是,如果我们将额外的维度添加为:

| 1 dx | * |x|  = | x + dx |
| 0  1 |   |1|    |      1 |

然后我们忘记了新的额外维度,我们得到:

x + dx

如我们所愿。

这个2D转换非常重要,因此有一个名称:剪切转换

可视化此转换很酷:

图片来源

请注意如何平移每条水平线(固定y)。

我们刚好y = 1把这条线作为新的1D线,并用2D矩阵对其进行转换。

事情在3D中类似,其形式为4D剪切矩阵:

| 1 0 0 dx |   | x |   | x + dx |
| 0 1 0 dy | * | y | = | y + dy |
| 0 0 1 dz |   | z |   | z + dz |
| 0 0 0  1 |   | 1 |   |      1 |

我们以前的3D旋转/缩放现在具有以下形式:

| a b c 0 |
| d e f 0 |
| g h i 0 |
| 0 0 0 1 |

杰米·金(Jamie King)的视频教程也值得一看。

仿射空间

仿射空间是我们所有3D线性变换(矩阵乘法)与4D剪切(3D平移)一起生成的空间。

如果我们将剪切矩阵与3D线性变换相乘,则总会得到以下形式:

| a b c dx |
| d e f dy |
| g h i dz |
| 0 0 0  1 |

这是最通用的仿射变换,可进行3D旋转/缩放和平移。

一个重要的特性是,如果我们将2个仿射矩阵相乘:

| a b c dx |   | a2 b2 c2 dx2 |
| d e f dy | * | d2 e2 f2 dy2 |
| g h i dz |   | g2 h2 i2 dz2 |
| 0 0 0  1 |   |  0  0  0   1 |

我们总是得到另一种形式的仿射矩阵:

| a3 b3 c3 (dx + dx2) |
| d3 e3 f3 (dy + dy2) |
| g3 h3 i3 (dz + dz2) |
|  0  0  0          1 |

数学家将此属性称为闭包,并且需要定义一个空间。

对我们来说,这意味着我们可以继续进行矩阵乘法以快乐地对最终变换进行逐个计算,这就是为什么首先使用二手矩阵而无需获得不仿射的更通用的4D线性变换的原因。

视锥投影

但是,等等,我们一直都在做一个更重要的变换:glFrustum,它使对象再扩大2 倍,显得小2 倍。

首先在以下网址获得有关glOrthovs的直觉glFrustumhttps//stackoverflow.com/questions/2571402/explain-the-usage-of-glortho/36046924#36046924

glOrtho可以只用平移+缩放来完成,但是如何glFrustum用矩阵实现呢?

假设:

  • 我们的眼睛在原点,看着-z
  • 屏幕(靠近平面)位于z = -1长度为2的正方形处
  • 视锥的远平面在 z = -2

如果仅允许我们使用以下类型的更通用的4个向量:

(x, y, z, w)

w != 0,此外,我们确定每一个(x, y, z, w)(x/w, y/w, z/w, 1),然后用矩阵截锥转型将是:

| 1 0  0 0 |   | x |   |  x |               | x / -z |
| 0 1  0 0 | * | y | = |  y | identified to | y / -z |
| 0 0  1 0 |   | z |   |  z |               |     -1 |
| 0 0 -1 0 |   | w |   | -z |               |      0 |

如果我们扔掉z,并w在最后,我们得到:

  • x_proj = x / -z
  • y_proj = y / -z

这正是我们想要的!我们可以验证一些值,例如:

  • 如果z == -1正好在我们要投影的飞机上,x_proj == x并且y_proj == y
  • 如果为z == -2,则x_proj = x/2:对象为一半大小。

注意glFrustum转换不是仿射形式的:不能仅通过旋转和平移来实现。

相加w并除以的数学“小技巧” 称为齐次坐标

另请参阅:相关的堆栈溢出问题:https : //stackoverflow.com/questions/2465116/understanding-opengl-matrices


@Downvoters,请解释一下,以便我学习和改进。
Ciro Santilli新疆改造中心法轮功六四事件

我个人认为这是漫长而又漫不经心的,解决原始问题的部分并没有什么新内容(其他答案没有很好地涵盖这一点),而其余部分则无关紧要,因此很难通过。
乔什

@JoshPetrie感谢您的反馈!我认为那些还不了解的人会更容易从我的答案中了解,因为它更能体现和直观。如果您发现完全不相关的特定错误或要点,请指出它们,以便我改善。干杯。
Ciro Santilli新疆改造中心法轮功六四事件

正如我所说,我认为大多数答案都是无关紧要的。问题问“为什么要使用4x4矩阵,为什么我们不能只加?” 答案很好地包含了诸如“是的,您可以添加,但是矩阵也可以平移/旋转/缩放”这样的解释,但是由于矩阵数学的工作原理,3x3无法对翻译进行编码,而4x4一罐。” 如果您在这堵文字墙中完全涵盖了这一点,将很难找到它。其余的内容是关于矩阵数学的入门知识,没有被问到,虽然它可以很好地回答另一个问题,但我认为这与这个问题不太合适。
乔什

1
我感谢对细节的关注。为了解决先前用户的顾虑,应将答案重新排列为“无法用3D矩阵表示翻译”。这回答了摆在眼前的问题,OP可以继续进行进一步的书面和热情的详细说明;这些更精细的细节是我在这里感兴趣的,因此我可能会有所偏颇,但这当然不是“漫无边际”。
dskinner '17

1

观看视频以了解模型,视图和投影的概念。

4x4矩阵不仅用于转换3D对象。而且还用于其他各种目的。

请查看此内容以了解世界上的顶点如何表示为4D矩阵以及如何对其进行变换。


1
这实际上并不能回答OP问题。
concept3d

编辑。听起来不错?
cegprakash
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.