我最近开始学习OpenGL,但在可视化矩阵及其在计算机图形学中的作用时遇到了问题。给定这样的4x4矩阵模板:
我假设像这样的每个矩阵都是世界空间中顶点的坐标。然后将它们中的几个放在一起并加阴影给一个对象?
但是为什么会有a Xx
,a Xy
和an Xz
?我读到它的轴是不同的(上,左,前),但仍然无法使意义变得有意义。
我最近开始学习OpenGL,但在可视化矩阵及其在计算机图形学中的作用时遇到了问题。给定这样的4x4矩阵模板:
我假设像这样的每个矩阵都是世界空间中顶点的坐标。然后将它们中的几个放在一起并加阴影给一个对象?
但是为什么会有a Xx
,a Xy
和an Xz
?我读到它的轴是不同的(上,左,前),但仍然无法使意义变得有意义。
Answers:
计算机图形学中的矩阵是赋予模型中每个坐标的变换。每个矩阵都是应用于坐标(3空间中的一个点)的多个变换的组合。
构建变换基于以下三种变换类型之一:平移,旋转和缩放。
翻译矩阵类似于:
和比例矩阵:
旋转矩阵如下所示:
要组合这些矩阵中的任何一个,只需将它们相乘即可。要将变换应用于顶点,只需将其乘以该顶点(如翻译图中所示)。
在计算机图形学中,我们使用矩阵对变换进行编码。
仅包含平移,旋转或缩放变换的矩阵具有一种常用的解释:矩阵的左上3x3仅包含旋转或缩放数据,下一行或右列包含平移数据。这不是一般性,但对于人们使用它的计算机图形表示的转换子集而言,经常足够适用。
类似地,在矩阵的值和矩阵表示的相应坐标系之间存在一种关系(我不应该总是注意到它总是“世界空间”)。左上的3x3列(或行)代表坐标系的X,Y和Z轴。
行是否表示轴还是列确实取决于您是否使用乘以as row vector * matrix
或的约定matrix * column vector
。在执行矩阵乘法时,两个矩阵的内部维数必须一致,因此将矢量表示为行矩阵还是列矩阵都会影响选择(OpenGL和传统数学方法倾向于使用列向量)。
我建议读一本关于线性代数的好书,或者至少看看Matrix和Quaternion FAQ以及这篇有关DirectX和OpenGL中矩阵布局的文章。
具有m
列和n
行的矩阵表示一个函数,该函数使用带有元素(或坐标)的向量*m
并生成带有n
元素的向量。
从中可以看出,当且仅当矩阵为正方形时,向量的维数才会改变。例如。您可以通过转换3D矢量,从2D转换2D等获得3D矢量。
*:在物理学中,矢量通常用于表示“移动”事物(例如速度或加速度)的力或其他“影响”。但是,没有什么可以阻止您使用向量来表示点或任何数字数组(某些库和编程语言甚至使用“向量”来表示“一维数组”)。对于与矩阵一起使用,任何东西都可以是向量的元素(甚至是字符串或颜色),只要您具有将它们与矩阵元素相乘,相减和相乘的方法即可。因此,名称vector,意思是“载体”-它为您携带或保存值。
那么,如果矩阵是一个函数,那么什么样的函数呢?该功能做什么?它的配方由矩阵的元素定义。让我们将其称为input u
,output v
,矩阵M
(M*u=v
然后乘积与相同f(u)=v
),并u(i)
给出的i
th个元素u
(例如,第二个元素是y坐标)。对于矩阵,M(i,j)
表示row i
,column j
。
element的构造(v(1)
结果中的第一个)由矩阵的第一行描述。u(1)
次M(1,1)
,u(2)
多次M(1,2)
,... u(i)
次M(1,i)
。矩阵有点像一种非常简单的编程语言,仅适用于编程功能,这些功能可以通过对输入进行混洗,将其添加到自身等来工作。**
想象一下您一次处理一个输出元素是很有帮助的,因此,您一次只使用矩阵的一行。您u
水平书写。您将其写在M
下面的第i行。您乘以上面/下面的每对,并在下面写下乘积,然后将乘积相加。对每一行重复操作以获取的每个元素v
。(现在您了解了为什么m
by n
矩阵必须对m
向量进行运算并产生n
向量。)
考虑这种情况的另一种方式-假设我们正在执行3D到3D转换,因此3x3矩阵(或通常称为3D转换,因为您可以假装此“功能”正在“移动” 3D点,即使实际上是只是改变数字)。假设第一行是[1 2 0]
。这意味着,要获取x的结果,请获取输入x的1,输入y的2和输入z的0。所以这真的是一个食谱。
**:如果矩阵是一种编程语言,那么它甚至不是图灵完整的。
如果它们都是适当大小的矩阵,则A*B
表示“先应用函数,B
然后应用A
”。您会看到为什么存在对乘法大小的约束,因为大小决定了输入和输出大小,而一个矩阵消耗了另一个矩阵的输出。为什么乘法意味着合并函数?更容易注意到它必须是。If A*u
与f(u)
和B*u
相同,g(u)
则f(g(u))
与和f(B*u)
相同A*(B*u)
。
同样,重复使用同一功能可以表示为幂,因为这A*A*A
意味着应用A
代表三次的功能。
进行类似的转换有什么好处new_x = 1*x+2*y+0*z
(如果第一行是[1 2 0])?这不是很明显,但是让我们采用另一个2D矩阵对此进行解释。矩阵为:
[ 0 1
1 0 ]
或[0 1; 1 0]
使用方便的Matlab表示法。这个矩阵做什么?它将像这样转换2D向量:对于结果的x,取输入y的1。对于结果y,取输入x的1。我们只是交换了输入的x和y坐标-这个矩阵反映了关于x = y线的点。这很有用!通过扩展,您会看到沿SW - NE线的所有矩阵均为1的情况都将反射。您还可以看到为什么身份矩阵给您输入(对于x输出,取x输入;对于y输出,取y输入...)。
现在您了解为什么符号是例如。Xx
,Yx
-他们的意思是多少投入X
,Y
等进入输出x
。
您还可以进行哪些其他转换?您可以通过采用一个单位矩阵来调整大小,但沿对角线的数字不能为1。例如,[2.5 0; 0 22.5]
将输入的每个坐标乘以2.5,如果将此矩阵应用于图片中的每个点,则图片的大小将为2.5。如果仅将2.5放在一行([2.5 0; 0 1]
)中,则将仅乘以x坐标,因此只能沿x拉伸。
其他矩阵可以进行其他转换,例如“倾斜”,这些转换具有不同程度的有用性。就个人而言,偏斜是我最不喜欢的,因为矩阵看起来很简单,但变换本身几乎不做任何事情,只需要弄乱图片即可。一个有用的是“旋转”-如何旋转一个点?绕原点逆时针(x, y)
旋转角度后,尝试计算出点的位置theta
。您会发现,新的x和y坐标都是通过将旧的x和y乘以theta的某些正弦和余弦得出的。您应该能够使用与该函数相对应的正弦和余弦轻松编写旋转矩阵。
使用非平方矩阵,您还可以更改输入的维数。将2D输入转换为3D并不是很有用,因为很难“制造”要放入新坐标的东西,但是将3D转换为2D非常有用。别的不说,这是你的电脑是如何知道项目*** 3D场景到2D图像绘制在显示器上。
由于向量可以容纳不同的事物,因此您甚至可以描述一个矩阵,该矩阵一次将字符串n个字符改组或将它们“相乘”或“相乘”(您必须提供乘法/加法函数)。
***:投影时,您将3D对象像雕塑一样,在其上照亮灯光,然后查看在墙壁上滴下什么样的2D阴影。
矩阵可以执行所有功能吗?不。以图形方式思考时,很难想象矩阵无法做到的事情(但它确实存在:例如,“漩涡”效果无法实现)。但是,这里有一个简单的例子:假设功能f
是这样的,f(u)
让你回来u
与方形的每一个元素。您将看到,您无法为此编写矩阵:使用矩阵,只有一种工具可以描述将坐标乘以常数的配方,而不能表达其他类似幂的函数。
****:这也是为什么它被称为线性代数的原因-幂函数是非线性的,绘制时不会形成直线。
现在,为什么您的示例中的矩阵是4×4?这不是4维空间吗?我们没有4D电脑,那为什么呢?对于与先前关于线性运算的观点有关的矩阵,这实际上是一个有趣的技巧。
关于不能使用矩阵完成哪些功能:将2D点向右移动2个单位的矩阵是什么(产生点(x+2, y)
?再次,我们陷入了困境。有一种方法可以使输入相乘,但无法相加对于2D工作,诀窍是假装您实际上不在2D空间中,而是在3D空间中,除了所有东西的高度(z坐标或第3个元素)始终为1(有点像2D宇宙如何)只是一个沿着3D宇宙的地板平放的“盘子”(在这种情况下,第三个坐标始终为0)。因此,您可以将此不可思议的最后一个坐标用作常数,因为您知道每个输入的坐标始终为1。
同样,要移动3D点,您需要4D坐标。这就是为什么您看到的所有3D转换矩阵都将[0 0 0 1]
作为最后一行的原因-您绝不能更改第4维,否则结果将太复杂而无法在3D中表示!
Xx Yx Zx Tx
...,而最后一行实际上0t 0t 0t 1t
是从中替换的Xt Yt Zt Tt
。为了(x+2, y)
从(x, y)
你可以去1x 0y 0z 2t
,会给你1*x + 0*y + 0*z + 2*1
因为t=1
对不对?几乎等于x + 2。哦,亲爱的,现在您可以用有趣的T值弄乱渲染了,不是吗?-grin-(长读,仍然是最佳价值,thx)
TL; DR版本:
[x y z]
每行中的前三个元素表示变换后的坐标系的单个基本向量。最后一个元素w
是翻译组件。
长版
如果您需要一个矩阵,当该矩阵应用于顶点时,可以使顶点绕原点旋转例如45度,则可以用代表变换轴的三个向量填充矩阵:
i
上的x
轴[1 0 0]
,但旋转了45度。这很简单[i_x i_y i_z]
,其中i_x
和i_y
是与X轴成45度内角的三角形的边:[cos(45) sin(45) 0]
。j
y轴上的点[0 1 0]
,但从该轴旋转了45度。将其草绘在一张纸上,您会看到,逆时针旋转时,组件变为[-sin(45) cos(45) 0]
。k
上的z
轴。在此示例中,z
由于我们在(屏幕对齐)xy平面中旋转,因此不会受到影响因此,我们有了三个新向量:i,j,k。可视化此方法的简单方法是仅使用X和Y轴并旋转整个十字排列。
我们如何将它们放在矩阵中?
i_x i_y i_z
j_x j_y j_z
k_x k_y k_z
要么
cos(45) sin(45) 0
-sin(45) cos(45) 0
0 0 1
如果将任何顶点乘以该矩阵,您将得到
v1_x = v_x cos(Θ) - v_y sin(Θ) + v_z * 0
V1_y = v_x*sin(Θ) + v_y cos(Θ) + v_Z * 0
V1_z = v_x * 0 + v_y * 0 + v_z * 1
为v = [1 0 0]
和Θ = 90°
,这成为v1 = [0 1 0]
对于翻译,我们添加第四行和第四列,并将翻译组件放在最后一列中。我们向顶点添加第四个分量,w
通常为1
。这样,当我们将顶点乘以矩阵时,w分量会导致将最后一列添加到输入顶点,因此将移动或平移顶点。我们称这些为“均匀坐标”。(出于我们的目的,“同质”仅表示w
每个向量中都有第4个分量,我们使用4x4矩阵而不是3x3。通常,您会看到使用4x3矩阵的着色器以避免发送几乎无用的第4行到GPU,这会消耗宝贵的内存和带宽。透视投影需要第4行,但不需要太多。)
希望这可以帮助。