如果我查看程序中的填充矩阵,则会看到翻译组件占据了第4、8和12个元素。
在开始之前,重要的是要了解:这意味着您的矩阵是行专业的。因此,您回答以下问题:
我的列主WVP矩阵已成功通过HLSL调用成功用于转换顶点:mul(vector,matrix),这将导致向量被视为行主矩阵,那么我的数学库提供的列主矩阵如何工作?
非常简单:您的矩阵是主要行。
如此多的人使用行优先矩阵或转置矩阵,以至于他们忘记了矩阵不是自然地定向的。因此他们看到了一个翻译矩阵:
1 0 0 0
0 1 0 0
0 0 1 0
x y z 1
这是转置的转换矩阵。那不是正常的翻译矩阵的样子。翻译在第四列而不是第四行中进行。有时,您甚至在教科书中看到了这一点,这简直是垃圾。
很容易知道数组中的矩阵是行还是列。如果是行优先的,则转换将存储在第3、7和11个索引中。如果列是主要列,则翻译将存储在第12、13和14个索引中。当然是零基索引。
您之所以感到困惑,是因为您实际上在使用行优先矩阵,却认为您正在使用列优先矩阵。
行与列专业是仅符号约定的说法是完全正确的。无论采用哪种约定,矩阵乘法和矩阵/矢量乘法的机制都是相同的。
变化的是结果的含义。
毕竟4x4矩阵只是4x4的数字网格。它不具有参考坐标系的变化。但是,一旦为特定矩阵分配了含义,您现在需要知道其中存储了什么以及如何使用它。
以我上面显示的翻译矩阵为准。那是一个有效的矩阵。您可以float[16]
通过以下两种方式之一存储该矩阵:
float row_major_t[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1};
float column_major_t[16] = {1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z, 0, 0, 0, 1};
但是,我说这个翻译矩阵是错误的,因为翻译位置不正确。我专门说过,它是相对于如何构建翻译矩阵的标准约定而换位的,应该看起来像这样:
1 0 0 x
0 1 0 y
0 0 1 z
0 0 0 1
让我们看看它们是如何存储的:
float row_major[16] = {1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z, 0, 0, 0, 1};
float column_major[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1};
请注意,column_major
是完全一样的row_major_t
。因此,如果我们采用适当的转换矩阵并将其存储为以列为主,则与转置该矩阵并将其存储为以行为主相同。
那就是仅是一种符号约定。实际上有两套约定:内存存储和转置。内存存储主要是列与行,而转置是正常与转置。
如果您有按行优先顺序生成的矩阵,则可以通过转置该矩阵的按列优先等效项来获得相同的效果。反之亦然。
矩阵乘法只能以一种方式完成:给定两个矩阵,并以特定的顺序将某些值相乘并存储结果。现在,,A*B != B*A
但是的实际源代码A*B
与的代码相同B*A
。它们都运行相同的代码来计算输出。
矩阵乘法代码不在乎矩阵是按列优先还是行优先顺序存储。
向量/矩阵乘法不能说相同。这就是为什么。
向量/矩阵相乘是个错误。这是不可能的。但是,您可以将一个矩阵乘以另一个矩阵。因此,如果您假设向量是矩阵,那么只需进行矩阵/矩阵乘法,就可以有效地进行向量/矩阵乘法。
可以将4D向量视为列向量或行向量。也就是说,可以将4D向量视为4x1矩阵(请记住:在矩阵表示法中,行数排在最前面)或1x4矩阵。
但这就是问题:给定两个矩阵A和B,A*B
仅当A的列数与B的行数相同时才定义。因此,如果A是我们的4x4矩阵,则B必须是4行的矩阵在里面。因此,您无法执行A*x
x为行向量的情况。同样,x*A
如果x是列向量,则无法执行。
因此,大多数矩阵数学库都做出了这样的假设:如果将向量乘以矩阵,就意味着要进行实际可行的乘法运算,而不是没有意义的乘法运算。
让我们为任何4D向量x定义以下内容。C
应该是的列向量矩阵形式x
,并且R
应该是的行向量矩阵形式x
。鉴于此,对于任何4x4矩阵A,都A*C
表示矩阵乘以A的列向量x
。并R*A
表示将行向量x
乘以A的矩阵。
但是,如果我们使用严格的矩阵数学来观察这一点,就会发现它们并不等效。R*A
不能与相同A*C
。这是因为行向量与列向量不同。它们不是相同的矩阵,因此它们不会产生相同的结果。
但是,它们以一种方式相关。的确是这样R != C
。但是,也确实是,其中T是转置运算。这两个矩阵互为换位。R = CT
这是一个有趣的事实。由于向量被视为矩阵,因此它们也存在列与行为主的存储问题。问题是它们看上去都一样。浮点数组是相同的,因此仅通过查看数据就无法分辨出R和C之间的区别。区别的唯一方法是如何使用它们。
如果您有任意两个矩阵A和B,并且A存储为行为主,B存储为列主,则将它们相乘是完全没有意义的。结果是胡说八道。好吧,不是真的。从数学上讲,您所获得的等同于做。或; 它们在数学上是相同的。AT*B
A*BT
因此,矩阵乘法只有在两个矩阵以相同的主要顺序存储时才有意义(记住:矢量/矩阵乘法只是矩阵乘法)。
那么,矢量是列优先还是行优先?如前所述,它既是又不是。仅当它用作列矩阵时才是列专业,而当它用作行矩阵时才是行专业。
因此,如果您有一个以列为主的矩阵A,则x*A
意味着...没有任何意义。好吧,这再次意味着,但这不是您真正想要的。同样,如果行大,则进行转置乘法。x*AT
A*x
A
因此,矢量/矩阵乘法的顺序会改变,具体取决于数据的主要顺序(以及是否使用转置矩阵)。
为什么在以下代码段中r!= r2
因为您的代码已损坏且存在错误。数学上,。如果没有得到此结果,则说明您的相等性测试错误(浮点精度问题)或矩阵乘法代码已损坏。A * (B * C) == (CT * BT) * AT
为什么pos3!= pos
因为那没有道理。唯一的正确方法是if 。但这仅适用于对称矩阵。A * t == AT * t
A == AT