mvp矩阵与矩阵变换
1. 矩阵基础
1.1 什么是齐次坐标
齐次坐标是在计算机图形学中常用的一种坐标表示方法,它在传统的笛卡尔坐标系的基础上增加了一个额外的维度,通常表示为(x, y, z, w)。 齐次坐标的主要优点是可以用来表示无穷远的点,并且可以通过一个矩阵乘法来表示旋转、缩放、平移等变换,这在计算机图形学中是非常有用的。
- 若w==1,则向量(x, y, z, 1)为空间中的点。
- 若w==0,则向量(x, y, z, 0)为方向。
1.2 为什么要用齐次坐标,而不是笛卡尔坐标?
简单来说平面坐标系,和三维坐标系都是笛卡尔坐标的一种,笛卡尔坐标还可以扩展到任意维,关键点是所有轴互相正交。
- 在三维图形中,3*3矩阵只能表示旋转无法表示平移,因此要引入多一个维度来表示。除此之外,引入这个维度的好处还在于可以表示点和方向。
1.3 矩阵变换
矩阵变换是一种在计算机图形学中常用的方法,用于表示和计算几何变换,如旋转、缩放和平移。这些变换通常用于改变物体的位置、方向和大小。
在二维空间中,旋转、缩放和平移可以分别用以下的2x2或3x3矩阵来表示:
- 旋转(θ为旋转角度):
[ cosθ -sinθ ] [ sinθ cosθ ]
- 缩放(sx和sy分别为x轴和y轴的缩放因子):
[ sx 0 ] [ 0 sy ]
- 平移(tx和ty分别为x轴和y轴的平移距离):
[ 1 0 tx ] [ 0 1 ty ] [ 0 0 1 ]
在三维空间中,旋转、缩放和平移可以分别用以下的3x3或4x4矩阵来表示。例如,沿z轴旋转、在各轴上缩放和平移的矩阵分别为:
- 沿z轴旋转(θ为旋转角度):
[ cosθ -sinθ 0 0 ] [ sinθ cosθ 0 0 ] [ 0 0 1 0 ] [ 0 0 0 1 ]
- 缩放(sx、sy和sz分别为x轴、y轴和z轴的缩放因子):
[ sx 0 0 0 ] [ 0 sy 0 0 ] [ 0 0 sz 0 ] [ 0 0 0 1 ]
- 平移(tx、ty和tz分别为x轴、y轴和z轴的平移距离):
[ 1 0 0 tx ] [ 0 1 0 ty ] [ 0 0 1 tz ] [ 0 0 0 1 ]
通过将这些矩阵与物体的顶点坐标相乘,我们可以得到变换后的顶点坐标。如果有多个变换需要应用,我们可以先将这些变换矩阵相乘,得到一个总的变换矩阵,然后再与顶点坐标相乘。
顶点坐标就是p=[x y z w]
,其中w取1,表示是一个点。
那矩阵变换就是M_(平移)M_(旋转)p = p'
,而M_(平移)M_(旋转)
可以通过矩阵结合律进行一个合并得到旋转平移矩阵,至于是先旋转还是平移就看运算顺序。在这个例子中是先旋转,再平移。按照从右往左的顺序,具体原理不一一说明。
这里可以更好说明为什么是
4*4
,因为平移需要4*4
的矩阵,所以就对旋转矩阵和缩放矩阵扩展一个维度,且不影响原来的矩阵乘积效果,然后通过矩阵结合律去合并,就可以得到一个能够表示对顶点进行任意旋转、缩放和平移的矩阵了。
1.4 空间变换
在矩阵变换的基础上,我们已经掌握了如何对一个点进行旋转、平移、缩放到另一个位置。接下来就开始讨论空间变换。
这里的理解其实很简单,只有两句话:
- 模型矩阵其实是可以看成一个将模型空间的原点转换到世界空间原点的变换。
- 对模型空间下的所有点(这些所有点组成一个模型,比如可能是一个车的造型),乘上这个矩阵,那就相当于将模型空间中的其他点按照相同的方式进行转换。所以原来所有的点,就从原来的模型空间,被移动到了新的空间。
2. 什么是mvp矩阵
MVP矩阵是在计算机图形学中常用的一个概念,它是Model-View-Projection三个矩阵的乘积,用于将物体的顶点坐标从其本地空间(Model Space)转换到屏幕空间(Screen Space)。
-
模型矩阵(Model Matrix):这个矩阵用于将物体的顶点坐标从模型空间转换到世界空间。模型空间是物体的本地坐标系统,而世界空间是一个全局的坐标系统,所有的物体都在这个空间中。模型矩阵通常包含了物体的位置、旋转和缩放信息。
-
视图矩阵(View Matrix):这个矩阵用于将物体的顶点坐标从世界空间转换到视图空间(也称为相机空间)。视图空间是以相机为中心的坐标系统,相机位于原点,朝向-z轴。视图矩阵通常包含了相机的位置和朝向信息。
-
投影矩阵(Projection Matrix):这个矩阵用于将物体的顶点坐标从视图空间转换到裁剪空间,然后通过除以齐次坐标w进行透视除法,得到归一化设备坐标(NDC),最后映射到屏幕空间。投影矩阵通常包含了相机的视野(FOV)、长宽比(Aspect Ratio)、近裁剪面(Near Clipping Plane)和远裁剪面(Far Clipping Plane)信息。
- 视口变换:在所有这些变换之后,我们还需要一个视口变换,将物体从裁剪空间转换到屏幕空间.这通常涉及到将物体的坐标从裁剪空间的-1到1范围映射到屏幕的像素坐标. 完整
将这三个矩阵相乘,就得到了MVP矩阵。在顶点着色器中,我们通常会用MVP矩阵来计算顶点的最终位置。
2.1 为什么要有mvp矩阵?
因为,我们使用了不同的坐标空间来描述物体的位置和方向,因此也就有了mvp矩阵。 是先有了下面这些空间,才有了mvp矩阵。 要理解mvp矩阵前,得先了解这些空间是干什么的。以下是这些空间的定义:
- 模型空间(Model Space):也称为物体空间,是物体的本地坐标系统。在模型空间中,物体的中心通常位于原点,物体的大小和方向都是相对于这个原点定义的。
引入模型空间
-
世界空间(World Space):也称为全局空间,是一个全局的坐标系统,所有的物体都在这个空间中。世界空间中的坐标是相对于一个固定的原点(通常是场景的中心)定义的。模型矩阵用于将物体的顶点坐标从模型空间转换到世界空间。
-
视图空间(View Space):也称为相机空间或者眼睛空间,是以相机为中心的坐标系统。在视图空间中,相机位于原点,朝向-z轴,上方向是y轴。视图矩阵用于将物体的顶点坐标从世界空间转换到视图空间。
- 裁剪空间(Clip Space):在裁剪空间中,所有可见的物体都在一个定义好的立方体(通常是[-1, 1] x [-1, 1] x [-1, 1])内。投影矩阵用于将物体的顶点坐标从视图空间转换到裁剪空间。然后,通过进行透视除法,将裁剪空间的坐标转换到归一化设备坐标(NDC)空间。在这个阶段,任何在这个立方体之外的物体都会被裁剪掉.
- 屏幕空间(Screen Space):这是最后的空间,物体的坐标是像素值,左上角是(0,0),右下角是(宽度,高度).这是通过视口变换实现的.
这些空间的转换是通过矩阵乘法实现的,MVP矩阵就是这些转换矩阵的乘积。 注意裁剪空间到屏幕空间的变换时通过视口变换实现的,因为这个不是通过矩阵运算表示的,所以mvp矩阵只包括从模型空间到裁剪空间,但不代表屏幕空间这个概念没有。
2.1.1 为什么要引入模型空间,而不是直接使用世界空间呢
引入模型空间(Model Space)的主要原因是为了方便地描述和操作物体。
在模型空间中,物体的中心通常位于原点,物体的大小和方向都是相对于这个原点定义的。这样,我们可以在一个简单和一致的坐标系统中定义和操作物体,而不需要考虑物体在世界中的具体位置和方向。
例如,如果我们想要旋转一个物体,我们可以简单地在模型空间中围绕原点进行旋转,而不需要考虑物体在世界空间中的位置。如果我们直接在世界空间中进行旋转,我们需要首先将物体移动到原点,然后进行旋转,最后再将物体移动回原来的位置。这显然比在模型空间中进行旋转要复杂得多。
此外,模型空间还允许我们独立地操作每个物体。每个物体都有自己的模型空间,我们可以在这个空间中独立地移动、旋转和缩放物体,而不会影响到其他物体。
总的来说,模型空间提供了一个简单、一致和独立的环境,使得我们可以更方便地描述和操作物体。
2.1.2 视图空间有啥用?
简单来说,视图空间描述了相机的位置和朝向信息。就是三维世界中,相机的位置。
视图矩阵(View Matrix)是通过平移和旋转操作得到的
2.1.3 怎么理解裁剪空间?
简单来说,世界坐标系上已经有很多模型了,相机的位置也已经确定了,现在就显示到屏幕了。 可以当成是相机坐标系上有一个平面,将世界坐标系上朝向这个平面的点,投影到这个平面。 这个平面就是所谓的裁剪空间,也是显示设备,即屏幕了。
投影矩阵是用来将3D空间中的点投影到2D平面上的,它包含了相机的视野(FOV)、长宽比(Aspect Ratio)、近裁剪面(Near Clipping Plane)和远裁剪面(Far Clipping Plane)等信息。 常见的有两种类型的投影矩阵:正交投影矩阵和透视投影矩阵。
2.2 投影矩阵
- 正交投影矩阵:
- 正交投影是一种线性投影,其中物体的大小不会随着深度的变化而变化.
- 这意味着远离相机的物体和靠近相机的物体大小看起来是一样的.这种投影常用于工程图/建筑图等需要精确测量的场合.
- 这个函数需要你提供视口的左/右/底/顶边界以及近/远裁剪面的距离
- 透视投影矩阵:
- 透视投影是一种非线性投影,其中物体的大小会随着深度的变化而变化.
- 这意味着远离相机的物体看起来会比靠近相机的物体小.
- 这种投影更符合人眼看世界的方式,因此常用于3D游戏和其他需要真实感的应用.
- 这个函数需要设置包括视野角度(FOV)/宽高比(aspect ratio)/近裁剪面(near clipping plane)和远裁剪面(far clipping plane)
2.3 视口变换
视口变换(Viewport Transform)是3D图形渲染流程中的一个步骤,它将裁剪空间中的坐标转换到屏幕空间的像素坐标系。
在裁剪空间中,所有可见的物体都在一个由-1到1的立方体中。视口变换将这个立方体映射到屏幕的像素坐标系,这通常涉及到将x和y坐标乘以屏幕的宽度和高度,然后再加上屏幕的左上角坐标。
视口变换包括两个步骤:
-
透视除法(Perspective Division):这一步将裁剪空间中的坐标除以它们的w分量。这一步将立方体变成了一个单位立方体,所有的坐标都在-1到1的范围内。
-
视口变换(Viewport Transform):这一步将单位立方体映射到屏幕的像素坐标系。
以下是一个简单的视口变换的例子:
vec2 viewportTransform(vec3 clipSpace)
{
float x = (clipSpace.x + 1.0) * 0.5 * screenWidth;
float y = (1.0 - clipSpace.y) * 0.5 * screenHeight;
return vec2(x, y);
}
这个函数首先将裁剪空间的坐标映射到0到1的范围,然后乘以屏幕的宽度和高度。注意,我们需要将y坐标翻转,因为在屏幕空间中,y轴是向下的,而在裁剪空间中,y轴是向上的。
99. quiz
1. 什么时候需要更改模型矩阵,什么时候更改模型坐标?
总的来说,当你需要改变物体的位置/方向或大小时,你需要更改模型矩阵.当你需要改变物体的形状时,你需要更改模型坐标. 更改大小”通常通过改变模型矩阵中的缩放因子来实现,而”更改形状”则需要直接修改模型的顶点坐标.
2. 为什么不可以统一都改模型坐标,而不改模型矩阵吗?
理论上,你可以通过直接修改模型坐标来改变物体的位置/方向和大小,但这通常不是一个好的做法.
首先,直接修改模型坐标会更加复杂和耗时.例如,如果你想将一个物体向右移动10个单位,你需要遍历所有的顶点,并将每个顶点的x坐标增加10.而如果你使用模型矩阵,你只需要将模型矩阵的平移部分增加10即可.
其次,直接修改模型坐标会破坏物体的原始数据.如果你需要恢复物体的原始位置/方向或大小,你需要保存一份原始的模型坐标,这会增加内存的使用.
最后,使用模型矩阵可以更好地利用图形硬件的能力.图形硬件可以高效地处理矩阵运算,而且许多图形API(如OpenGL和DirectX)都提供了对模型矩阵的直接支持.
因此,通常我们会优先使用模型矩阵来改变物体的位置/方向和大小,而只在需要改变物体的形状时才直接修改模型坐标.
3. 视图矩阵的eye, center, up是什么?
在MVP矩阵中,”eye”和”center”是相机的位置和观察目标的位置,up是相机的上方向(通常,我们选择(0.0, 1.0, 0.0)作为up参数,表示相机的顶部指向世界空间的上方)
- “eye”代表相机的位置,即相机在世界空间中的坐标.它定义了相机的位置和朝向.
- “center”代表观察目标的位置,即相机所看的点在世界空间中的坐标.它定义了相机的视线方向.也可以理解为焦点
- up是相机的上方向(通常,我们选择(0.0, 1.0, 0.0)作为up参数,表示相机的顶部指向世界空间的上方)
这三个参数一起定义了相机的位置和朝向,用于计算视图矩阵.视图矩阵将物体从世界空间转换到相机空间,使得物体相对于相机的位置和方向进行变换. 一般设定了eye center和up,函数库会自动求解4*4的视图矩阵。
附录
1. 点乘和叉乘
点乘(Dot Product)和叉乘(Cross Product)是向量运算中的两种基本运算。
-
点乘:点乘是一种二元运算,它接受两个向量作为输入,并产生一个标量作为输出。在二维或三维空间中,两个向量A和B的点乘定义为:
A·B = A B cosθ 其中, A 和 B 分别是A和B的长度,θ是A和B之间的角度。在计算机图形学中,点乘常常用来计算两个向量之间的角度,或者判断两个向量是否垂直。 -
叉乘:叉乘也是一种二元运算,但它接受两个向量作为输入,并产生一个新的向量作为输出。在三维空间中,两个向量A和B的叉乘定义为:
A×B = A B sinθn 其中,n是垂直于A和B的单位向量,方向由右手法则决定。叉乘的结果向量的长度等于原来两个向量构成的平行四边形的面积,方向垂直于这两个向量。在计算机图形学中,叉乘常常用来计算两个向量的法向量,或者判断两个向量是否平行。
在实际计算中,点乘和叉乘通常通过向量的各个分量来计算。例如,如果A = [Ax, Ay, Az],B = [Bx, By, Bz],那么:
A·B = AxBx + AyBy + Az*Bz
A×B = [AyBz - AzBy, AzBx - AxBz, AxBy - AyBx]
2. 点乘和投影
点乘和投影之间有着密切的关系。在向量运算中,点乘可以用来计算一个向量在另一个向量上的投影。
假设我们有两个向量A和B,我们想要找到A在B上的投影。这个投影是一个向量,它的方向与B相同,长度等于A在B方向上的分量。我们可以通过以下步骤计算这个投影:
-
首先,我们计算A和B的点乘,得到一个标量值:A·B = A B cosθ,其中θ是A和B之间的角度。 -
然后,我们将这个标量值除以B的长度,得到A在B方向上的分量:A·B/ B = A cosθ。 -
最后,我们将这个分量乘以B的单位向量,得到投影向量:(A·B/ B ) * (B/ B ) = (A·B/ B ^2) * B。
所以,A在B上的投影可以通过点乘和除法运算得到,公式如下:
Proj_B(A) = (A·B/ | B | ^2) * B |
这就是点乘和投影之间的关系。
4. 屏幕空间的坐标系是怎么样的?
在计算机图形学中,屏幕的坐标系通常是这样的:
- 原点(0,0)位于屏幕的左上角。
- x轴的正方向是向右,所以当你增加x值时,你会向屏幕的右边移动。
- y轴的正方向是向下,所以当你增加y值时,你会向屏幕的下方移动。
3. 视锥体
这是一个在3D空间中定义了相机视野的体积.任何在这个体积之外的物体都不会被渲染.