MVP变换(Model-View-Projection Matrices)#
MVP变换用来描述视图变换的任务,即将虚拟世界中的三维物体映射(变换)到二维坐标中。
MVP变换分为三步:
- 模型变换(model tranformation):将模型空间转换到世界空间(找个好的地方,把所有人集合在一起,摆个pose)
- 摄像机变换(view tranformation):将世界空间转换到观察空间(找到一个放相机的位置,往某一个角度去看)
- 投影变换(projection tranformation):将观察空间转换到裁剪空间(茄子!)
视图变换(View)#
视图变换的目的是变换Camera位置到原点,上方为Y,观察方向为-Z
Camera的y轴正方向向上,z轴方向是\(\vec{x} \times \vec{y}\)右手系)
对物体进行运动,摄像机会跟随着一起运动保持相对位置不变
怎么写出数学表示
通过\(V_{\text{view}}\)变换相机,在数学上怎么表示?
- 将e平移到零点
- 旋转g到−Z
- 旋转t到Y
- 旋转
G x T到X

可以将其拆解成两个部分: 平移+旋转
首先将相机从e平移到标准原点的位置
$$ T_{VIEW} = \begin{bmatrix} 1 & 0 & 0 & -x_e \\ 0 & 1 & 0 & -y_e \\ 0 & 0 & 1 & -z_e \\ 0 & 0 & 0 & 1 \end{bmatrix} $$由于旋转矩阵具有正交性,因此它的逆矩阵就等于它的转置矩阵.
$$ \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \cdot \begin{bmatrix} x_{\hat{g}\times\hat{t}} & x_t & x_{-g} & 0 \\ y_{\hat{g}\times\hat{t}} & y_t & y_{-g} & 0 \\ z_{\hat{g}\times\hat{t}} & z_t & z_{-g} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} = E \cdot \begin{bmatrix} x_{\hat{g}\times\hat{t}} & x_t & x_{-g} & 0 \\ y_{\hat{g}\times\hat{t}} & y_t & y_{-g} & 0 \\ z_{\hat{g}\times\hat{t}} & z_t & z_{-g} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} $$在通过正交矩阵的性质(正交矩阵的逆等于它的转置矩阵),可以求出:
总结:
- 让物体和相机一起变换。
- 直到相机位于原点,头朝上(Y),看向 −Z
投影变换(Projection)#
投影变换分为两种:
- 正交投影(Orthogonal projection)变换:透视线平行
- 透视投影(Perspective projection)变换:透视线相交,近大远小
简单来讲,透视投影相当于两点透视或三点透视,有透视畸变。正交投影相当于是基于坐标的轴测图

正交投影 (Orthogonal projection)#
一种简单的理解方式
相机位于原点,朝向 -Z 方向,向上为 Y 方向
丢弃 Z 坐标
将得到的矩形平移并缩放到
[-1, 1]²范围内
我们希望将一个长方体区域
[l, r] × [b, t] × [f, n](左右 X 下上 X 远近)映射到立方体
[-1, 1]³

方法:
- 现将标准立方体拉到原点
- 后将x,y,z轴各自**伸缩到
[−1,1]
变换顺序:先移动(中点移动到原点),再缩放(基向量缩放比例为\(\frac{2}{\text{长} / \text{宽} / \text{高}}\)
因为相机朝向-z方向(右手系),此时n > f,这也是 OpenGL 用左手系( f > n )的原因。
正交投影矩阵(Orthographic Projection Matrix)#
$$ M_{\text{ortho}} = \underbrace{ \begin{bmatrix} \frac{2}{r-l} & 0 & 0 & 0 \\ 0 & \frac{2}{t-b} & 0 & 0 \\ 0 & 0 & \frac{2}{n-f} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} }_{\text{缩放矩阵 } S} \cdot \underbrace{ \begin{bmatrix} 1 & 0 & 0 & -\frac{r+l}{2} \\ 0 & 1 & 0 & -\frac{t+b}{2} \\ 0 & 0 & 1 & -\frac{n+f}{2} \\ 0 & 0 & 0 & 1 \end{bmatrix} }_{\text{平移矩阵 } T} $$合并后形式
$$ M_{\text{ortho}} = \begin{bmatrix} \frac{2}{r-l} & 0 & 0 & -\frac{r+l}{r-l} \\ 0 & \frac{2}{t-b} & 0 & -\frac{t+b}{t-b} \\ 0 & 0 & \frac{2}{n-f} & -\frac{n+f}{n-f} \\ 0 & 0 & 0 & 1 \end{bmatrix} $$参数说明:
l, r→ 左右边界(left / right)b, t→ 下上边界(bottom / top)f, n→ 远近裁剪面(far / near),注意在右手系中通常n > f(如 n = -0.1, f = -100)
透视投影 (Perspective projection)#
- 透视投影是应用最广泛的投影。
- 近大远小。
- 平行线看上去不再平行。
回顾:齐次坐标的性质
- (x, y, z, 1)、(kx, ky, kz, k ≠ 0)、(xz, yz, z², z ≠ 0) 都表示三维空间中的同一个点 (x, y, z)
- 例如:(1, 0, 0, 1) 和 (2, 0, 0, 2) 都表示点 (1, 0, 0)
简单,但很有用
如何做透视投影#

更好理解的方式是想象原屏幕上的四个顶点,我们把他们挤到和近平面同一个高度上。换言之,我们把他“挤”成了空间中的一个长方体。然后做正交投影就行了。
在挤压的操作中我们规定几点:
- 近平面上的点永远不变(想象你要把窗户外面的东西画到窗户上,窗户上的东西不会改变)。
- 远平面的点z值不会发生变化。
- 远平面的中心点不会变。
研究挤压:
从侧面观察挤压过程
根据相似三角形,可以得出x和x' 与 y和y'的对应关系:
原本的坐标根据齐次坐标表示会变成(第二步同乘以 z)
$$ \begin{bmatrix} x \\ y \\ z \\ 1 \end{bmatrix} \rightarrow \begin{bmatrix} nx/z \\ ny/z \\ \text{unknown} \\ 1 \end{bmatrix} \overset{\text{mult. by } z}{==}\begin{bmatrix} nx \\ ny \\ z \cdot \text{unknown} \\ z \end{bmatrix} $$把这个变换用齐次坐标矩阵表示:
$$ M_{(4 \times 4)} \begin{bmatrix} x \\ y \\ z \\ 1 \end{bmatrix} == \begin{bmatrix} nx \\ ny \\ z \cdot \text{unknown} \\ z \end{bmatrix} $$根据矩阵乘法规则,我们可以反推出矩阵 M 的结构如下:
$$ M_{persp \to ortho} = \begin{pmatrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ ? & ? & ? & ? \\ 0 & 0 & 1 & 0 \end{pmatrix} $$投影 == 挤压 x y + 正交投影,look at -z 的时候,z 上的坐标被干掉了,所以投影变换前后 z 的坐标不变
第三行负责计算变换后的 z 坐标(z’)
- 近裁剪平面上的任意点,其 z 值不会改变
- 远裁剪平面上的任意点,其 z 值也不会改变
我们再利用下面两条性质就可以得到未知的部分
- 近平面上的点不变
- 远平面中心点不变
- 条件一:近平面上的任意点(令
unknown=n,z=n): $$ M \cdot P_{near} = \begin{pmatrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ 0 & 0 & A & B \\ 0 & 0 & 1 & 0 \end{pmatrix} \begin{bmatrix} x \\ y \\ n \\ 1 \end{bmatrix} = \begin{bmatrix} nx \\ ny \\ An + B \\ n \end{bmatrix} $$
因为不涉及旋转,所以第三行与x,y无关。
$$ \text{第三行运算结果:} \quad \begin{bmatrix} 0 & 0 & A & B \end{bmatrix} \cdot \begin{bmatrix} x \\ y \\ n \\ 1 \end{bmatrix} = n^2 $$即:
$$ An + B = n^2 \tag{1} $$- 条件二:远平面中心点不变
远平面的中心点满足
x=0,y=0,z=f:
将其乘以矩阵 M ,关注结果向量的第三分量(即变换后的 z′):
同理可得:
$$ \text{第三行运算结果:} \quad \begin{bmatrix} 0 & 0 & A & B \end{bmatrix} \cdot \begin{bmatrix} 0 \\ 0 \\ f \\ 1 \end{bmatrix} = f^2 $$即:
$$ Af + B = f^2 \tag{2} $$求解方程组
因此可以得到(1)和 (2)两个关系式,联立方程 (1) 和 (2)::
- 第一步:消元求解
A用方程 (2) 减去方程 (1):
利用平方差公式展开右边:
$$A(f - n) = (f - n)(f + n)$$解得 A :
- 第二步:代入求解
B将A=f+n代入方程 (1):
展开并化简:
$$fn + n^2 + B = n^2$$解得 B:
最终得到:
$$ \begin{cases} A = n + f \\ B = -nf \end{cases} $$求得变换矩阵为:
$$ M_{\text{persp} \to \text{ortho}} = \begin{bmatrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ 0 & 0 & n + f & -nf \\ 0 & 0 & 1 & 0 \end{bmatrix} $$透视投影数学表示和总结#
总结归纳下:
透视投影的本质可以总结为 “先变形,后归一化” 的两步走策略。
想象你在拍一张照片:
- 挤压:先把眼前立体的风景,通过某种魔法压扁成一张平面的底片(此时还没透视感,只是数据变了)。
- 正交:把这张底片裁剪成标准尺寸。
- 除法:当你透过镜头看这张底片时,大脑(GPU)自动把它还原成立体的画面,远的就远,近的就近。
🎯 核心逻辑:两步变换
挤压变形 (Shear & Scale)
- 动作:把“金字塔形”的视锥体(近小远大),强行挤压成一个“长方体”。
- 目的:让原本复杂的透视关系,变成简单的正交关系。
- 关键操作:利用齐次坐标 w 分量,让 zz值影响 x,yx,y 的缩放(即 x′=x⋅n zx′=x⋅zn ),实现“近大远小”的数学基础。
正交投影 (Orthographic)
- 动作:对挤压后的长方体进行标准的平移和缩放。
- 目的:将长方体映射到标准设备坐标空间 (NDC, 即 [−1,1]3[−1,1]3 )。
- 结果:此时所有物体都变成了正交视图,但深度信息 ( zz ) 已被特殊编码保留。
透视除法 (Perspective Division) —— 隐式步骤
- 动作:GPU 自动执行 (x,y,z)/w(x,y,z)/w 。
- 效果:因为第一步中 ww被设为了 z ,除以 ww 后,远处的点坐标变小,近处的点坐标变大,透视效果正式显现。
投影矩阵的变换 最终透视投影矩阵 = 正交投影矩阵 × 透视转正交矩阵
$$ M_{\text{persp}} = M_{\text{ortho}} \cdot M_{\text{persp} \to \text{ortho}} $$整理后就是:
$$ M_{\text{persp}} = \underbrace{ \begin{bmatrix} \frac{2}{r-l} & 0 & 0 & 0 \\ 0 & \frac{2}{t-b} & 0 & 0 \\ 0 & 0 & \frac{2}{n-f} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} }_{\text{缩放矩阵 } S} \cdot \underbrace{ \begin{bmatrix} 1 & 0 & 0 & -\frac{r+l}{2} \\ 0 & 1 & 0 & -\frac{t+b}{2} \\ 0 & 0 & 1 & -\frac{n+f}{2} \\ 0 & 0 & 0 & 1 \end{bmatrix} }_{\text{平移矩阵 } T} \cdot \underbrace{ \begin{bmatrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ 0 & 0 & n+f & -nf \\ 0 & 0 & 1 & 0 \end{bmatrix} }_{M_{\text{persp} \to \text{ortho}}} $$拆解说明:
这实际上是说:
标准正交投影矩阵
M_ortho= 缩放矩阵 S × 平移矩阵 T
也就是说,作者把原本一个复杂的 M_ortho 拆成了两个更直观的几何操作:
平移 T:将视景体中心移到原点
→ 对应平移量:(-(r+l)/2, -(t+b)/2, -(n+f)/2)缩放 S:将视景体缩放到 [-1,1]³
→ 对应缩放因子:(2/(r-l), 2/(t-b), 2/(n-f))
虽然图中保留了完整分解,但在实际编程中(如 OpenGL),我们通常使用简化后的单矩阵版本:
$$ M_{\text{persp}} = \begin{bmatrix} \frac{2n}{r-l} & 0 & \frac{l+r}{l-r} & 0 \\ 0 & \frac{2n}{t-b} & \frac{b+t}{b-t} & 0 \\ 0 & 0 & \frac{n+f}{n-f} & \frac{2fn}{f-n} \\ 0 & 0 & 1 & 0 \end{bmatrix} $$视口变换#
经过上述MVP变换以后,所有物体都在 [-1,1]^3 的cube中,下一步需要将他们花在屏幕上,这个过程就是光栅化
视锥#
视锥表示看起来像顶部切割后平行于底部的金字塔的实体形状。这是透视摄像机可以看到和渲染的区域的形状。
定义视锥:
- 长宽比 Aspect
- 垂直的角度 FovY
利用视锥来获取物体的长宽高

需要注意的是:
- 近平面总高度 = 2t
- 近平面总宽度 = 2r
公式解析
- 计算半高度
t$$ \tan\left(\frac{\text{fovY}}{2}\right) = \frac{t}{|n|} $$
fovY / 2: 这是垂直视野角的一半。如上图所示,它构成了一个直角三角形的一个锐角。|n|: 这是近平面距离(near plane distance),即从摄像机原点(0,0,0)到近平面的距离。因为通常使用右手坐标系且摄像机朝向-Z轴,所以n是一个负数,这里取绝对值|n|作为三角形的邻边长度。t: 这是我们要求的对边长度,即从中心线到近平面上边缘的距离。
利用三角函数里面的正切函数求解(tan = 对边/邻边),可以得到t:
$$ t = |n| \cdot \tan\left(\frac{\text{fovY}}{2}\right) $$现在有了摄像机的近平面距离 |n| 和 垂直视野角 fovY,就可以精确计算出近平面的半高 t
- 计算半宽度
r$$ \text{aspect} = \frac{r}{t} $$
aspect: 这是屏幕或图像的宽高比,通常是已知的(例如 16:9 的屏幕,aspect = 16/9 ≈ 1.778)。r: 这是我们要计算的,即从中心线到近平面右边缘的距离(半宽)。t: 这是我们刚刚通过第一个公式计算出来的半高。
利用宽高比定义(宽高比 = 总宽 / 总高)将公式变形:
$$ r = t \cdot \text{aspect} $$现在算出半高 t 并且知道宽高比 aspect 的情况下,可以计算出近平面的半宽 r
屏幕(Screen)#
- 二维数组,数组元素为像素,分辨率 = 数组尺寸
- 属于光栅显示器,典型的光栅成像设备
光栅(Raster)#
- “Raster” 在德语中就是 “screen” 的意思。
- (将图形画在屏幕上) 光栅化” 就是把几何图形(三角形、线条等)绘制到屏幕上的过程,即把矢量/连续空间的数据转换为离散的像素值。
像素(Pixel <- Picture element)#
- 像素是一个颜色均匀的小正方形
- 颜色混合而成(红、绿、蓝)
屏幕空间(Screen space)#

规定:
- 像素的索引形式为 (x, y),其中 x 和 y 均为整数
- 像素的索引范围是从 (0, 0) 到 (width - 1, height - 1)
- 像素 (x, y) 的中心位于 (x + 0.5, y + 0.5)
- 屏幕覆盖的范围是从 (0, 0) 到 (width, height)
视口变换公式#
做的事情:
先不考虑z轴,把MVP后处于标准立方体映射到屏幕上。即
把虚拟世界中的任意物体顶点,最终映射到屏幕像素坐标上:
$$ M_{\text{total}} = M_{\text{viewport}} \cdot M_{\text{projection}} \cdot M_{\text{view}} \cdot M_{\text{model}} $$注意:矩阵乘法不满足交换律! 必须按“模型 → 视图 → 投影 → 视口”的顺序相乘
| 步骤 | 矩阵名 | 作用 | 输入空间 → 输出空间 |
|---|---|---|---|
| 1.模型变换 | M_model | 将物体从本地坐标系移到世界坐标系 | 模型空间 → 世界空间 |
| 2️.视图变换 | M_view | 将世界坐标系转换为以相机为中心的坐标系 | 世界空间 → 相机空间 |
| 3️.投影变换 | M_projection | 将 3D 场景投影到 2D 平面,并归一化到 NDC | 相机空间 → 裁剪空间 → NDC |
| 4️.视口变换 | M_viewport | 将 NDC 映射到实际屏幕像素坐标 | NDC → 屏幕空间 |
