Games101学习笔记(持续更新中)

一、Lecture 01 计算机图形学概述

(一)什么是图形学

Computer Graphics,使用计算机来合成和处理视觉信息的技术 / 领域。

(二)为什么学图形学

1、图形学主要应用

  • 电子游戏(游戏画面、渲染等)
  • 电影(特效、面部捕捉、渲染等)
  • 设计(CG/概念图)
  • 可视化(操纵视觉信息的方法)
  • 虚拟现实VR 与 增强现实 AR
  • 数字插画
  • 模拟仿真
  • 图形用户接口 GUI
  • 字体设计 Typography

2、图形学的难点

  • 实现虚拟世界逼真的交互
  • 对真实世界物理规律的深刻理解
  • 新的计算方法、显示方法、新技术

3、技术挑战

  • 透视、投影、曲线、曲面相关数学原理
  • 光照与着色的物理机制
  • 三维形状的表示与运算
  • 动画与仿真
  • 三维图形软件编程与硬件

4、为什么要学

Computer Graphics is AWESOME!

(三)主要课程

  • 光栅化
  • 曲线和曲面
  • 光线追踪
  • 动画 / 模拟 / 仿真

(四)这门课不说什么

  • OpenGL / DirectX / Vulcan(图形学 API)
  • Shader(着色器)
  • Maya / 3DS / Blender(3D建模)
  • Unity / Unreal(游戏开发引擎)
  • Computer Vision / Deep Learning(计算机视觉/深度学习)
    • 两者都不属于计算机图形学范畴
    • 计算机视觉:一切需要猜测的内容,比如识别,分析理解东西
    • 深度学习:比如人脸生成,是在图像层面上的操作

计算机图形学与计算机视觉

  • 图形学不是计算机视觉。
  • 计算机视觉:猜测、预测、分析处理
  • 计算机视觉是理解这个世界,计算机图形学是创造这个世界

image-20260405000959571

当今各个学科结合越来越紧密,边界越来越模糊。

二、Lecture 02 向量与线性代数

(一)图形学依赖的知识

  • 基础数学 —— 线性代数、微积分、统计学
  • 基础物理 —— 光学、力学
  • 其他 —— 信号处理、数值分析
  • 以及一些美感

(二)向量

1、向量

具有大小和方向的量,没有绝对的起点。记作 \vec{a} 或 粗体 \boldsymbol{a}。用矩阵表示为 \mathbf{A} = \begin{pmatrix} x \\ y \end{pmatrix}、\mathbf{A}^T = (x,\ y)。

2、向量的模长

向量的模长(长度),记作 ∥a∥,计算公式为 \|\mathbf{A}\| = \sqrt{x^2 + y^2}。

3、向量归一化

长度为1的向量,计算方式为 \hat{\boldsymbol{a}} = \dfrac{\boldsymbol{a}}{|\boldsymbol{a}|}。

4、向量加法

使用三角形法则或者平行四边形法则。

5、笛卡尔坐标系

让向量起点为坐标原点,这样可以使用基向量 X、Y 线性组合表示一个向量。X 和 Y 通常为正交单位向量(互相垂直的单位向量)。

6、向量点乘(Dot)

  • 说明: \vec{a} \cdot \vec{b} 可以看作是 \vec{a} 与 \vec{b} 在 \vec{a} 上的投影 的长度的乘积。
  • 几何定义:\vec{a} \cdot \vec{b} = \|\vec{a}\| \|\vec{b}\| \cos\theta。
  • 点积求夹角余弦:\cos\theta = \frac{\vec{a} \cdot \vec{b}}{\|\vec{a}\| \|\vec{b}\|},单位向量则为 \cos\theta = \hat{a} \cdot \hat{b}。
  • 笛卡尔坐标系下的点乘:\vec{a} \cdot \vec{b} = \begin{pmatrix} x_a \\ y_a \end{pmatrix} \cdot \begin{pmatrix} x_b \\ y_b \end{pmatrix} = x_a x_b + y_a y_b
  • 性质:
    • 交换律: \vec{a} \cdot \vec{b} = \vec{b} \cdot \vec{a}
    • 分配律: \vec{a} \cdot (\vec{b} + \vec{c}) = \vec{a} \cdot \vec{b} + \vec{a} \cdot \vec{c}
    • 数乘结合律: (k\vec{a}) \cdot \vec{b} = \vec{a} \cdot (k\vec{b}) = k(\vec{a} \cdot \vec{b})
  • 应用:
    • 计算两个向量之间的夹角
    • 计算一个向量在另一个向量上的投影
    • 衡量两个方向的接近程度(越接近\|\vec{a}\| \|\vec{b}\|,两向量越同向)
    • 判断方向是向前还是向后

7、向量叉乘(Cross)

  • 说明:叉乘结果与两个原向量正交(垂直),右手坐标系下,方向由右手螺旋定则确定:以 \vec{a} \times \vec{b} 为例,右手四指从a指向b并握紧,最终拇指朝向就是叉乘结果向量的方向。
  • 模长公式:\|\vec{a} \times \vec{b}\| = \|\vec{a}\| \|\vec{b}\| \sin\phi,表示 ab 两向量所组成的平行四边形的面积。
  • 性质:
    • 坐标轴单位向量的叉乘:\vec{x} \times \vec{y} = +\vec{z}(排列组合共6种)
    • 反交换律:\vec{a} \times \vec{b} = -\vec{b} \times \vec{a}
    • 自身叉乘为零向量:\vec{a} \times \vec{a} = \vec{0}
    • 分配律:\vec{a} \times (\vec{b} + \vec{c}) = \vec{a} \times \vec{b} + \vec{a} \times \vec{c}
    • 数乘结合律:\vec{a} \times (k\vec{b}) = k(\vec{a} \times \vec{b})
  • 笛卡尔坐标系下的叉乘:
    • 分量形式: \vec{a} \times \vec{b} = \begin{pmatrix} y_a z_b - y_b z_a \\ z_a x_b - x_a z_b \\ x_a y_b - y_a x_b \end{pmatrix}
    • 矩阵形式:\vec{a} \times \vec{b} = A^* \vec{b} = \begin{pmatrix} 0 & -z_a & y_a \\ z_a & 0 & -x_a \\ -y_a & x_a & 0 \end{pmatrix} \begin{pmatrix} x_b \\ y_b \\ z_b \end{pmatrix}
  • 应用:
    • 判断两个向量左右关系。
    • 判断一个点位于凸多边形的“内外”关系。

8、标准正交基 / 坐标系

坐标系对表示点、位置、空间坐标至关重要,核心的问题就是不同坐标系 / 基之间的变换。

  • 标准正交坐标系:满足以下条件的 3 个向量构成标准正交基

    • 单位向量: \|\vec{u}\| = \|\vec{v}\| = \|\vec{w}\| = 1
    • 正交: \vec{u} \cdot \vec{v} = \vec{v} \cdot \vec{w} = \vec{u} \cdot \vec{w} = 0
    • 第三个向量由前两个叉乘得到: \vec{w} = \vec{u} \times \vec{v} \quad
  • 向量分解(投影分解):

    • 任意向量都可以用标准正交基线性表示,本质是在三个基向量上的投影之和
    • \vec{p} = (\vec{p} \cdot \vec{u})\vec{u} + (\vec{p} \cdot \vec{v})\vec{v} + (\vec{p} \cdot \vec{w})\vec{w}

(三)矩阵

1、矩阵

可以理解为一个由数字组成的二维数组,在图形学中被广泛用于变换,比如平移、旋转、错切、缩放等。

2、矩阵加法与标量乘法

这个比较简单,对应元素分别操作即可,这里就不讲了。

3、矩阵乘法

  • 最终的矩阵大小:(M \times N) \cdot (N \times P) = (M \times P)
  • 性质:
    • 不满足交换律:大部分情况下 AB \neq BA
    • 结合律:(AB)C = A(BC)
    • 分配律:A(B+C) = AB + AC 、 (A+B)C = AC + BC

4、矩阵的转置

  • 意义:交换矩阵行与列 \begin{pmatrix} 1 & 2 \\ 3 & 4 \\ 5 & 6 \end{pmatrix}^T = \begin{pmatrix} 1 & 3 & 5 \\ 2 & 4 & 6 \end{pmatrix}
  • 性质:(AB)^T = B^T A^T

5、单位矩阵

特征:I_{3\times3} = \begin{pmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{pmatrix}

6、逆矩阵

  • 必须满足:AA^{-1} = A^{-1}A = I
  • 矩阵乘积的逆: (AB)^{-1} = B^{-1}A^{-1}

7、向量乘法转换为矩阵乘法:

  • 将向量视为 m 行 1 列的列矩阵。
  • 点乘:\vec{a} \cdot \vec{b} = \vec{a}^T \vec{b} = \begin{pmatrix} x_a & y_a & z_a \end{pmatrix} \begin{pmatrix} x_b \\ y_b \\ z_b \end{pmatrix} = \begin{pmatrix} x_a x_b + y_a y_b + z_a z_b \end{pmatrix}
  • 叉乘:\vec{a} \times \vec{b} = A^* \vec{b} = \begin{pmatrix} 0 & -z_a & y_a \\ z_a & 0 & -x_a \\ -y_a & x_a & 0 \end{pmatrix} \begin{pmatrix} x_b \\ y_b \\ z_b \end{pmatrix}

三、Lecture 03 变换

(一)为什么学变换

因为它从应用来看很重要

  • 模型变换:在静态场景中移动摄像机、控制机器人手臂旋转、电影入场标题字母的缩放变换。
  • 视图变换:摄像机拍照中将 3D 转成 2D 的一个投影变换。

(二)二维变换

1、缩放变换 Scale Matrix

分为统一的缩放变换和非统一的缩放变换。统一表示各个分量缩放都是一致的,非统一则表示各个分量缩放不一致,如下图就是非统一的缩放。
M_{scale} = \begin{bmatrix} s_x & 0 \\ 0 & s_y \end{bmatrix}
image-20261008164901902

2、反射矩阵 Reflection Matrix

将图像按照坐标轴翻转,分为水平翻转和垂直翻转,如下面就是图像按照 y 轴进行水平翻转的变换矩阵。
M_{refletion} = \begin{bmatrix} -1 & 0 \\ 0 & 1 \end{bmatrix}
image-20261008170130561

3、切变矩阵 Shear Matrix

分为X方向切变和Y方向切变,如下图就是X方向的切变,图像沿X轴倾斜,具体点就是 y=0 的地方 x 不变,再往上就是 x坐标发生了向右偏移,而 y 坐标始终不变。其中这个 x 变化根据三角函数可以得出是往右偏移了 ay 个单位。
M_{shear} = \begin{bmatrix} 1 & a \\ 0 & 1 \end{bmatrix}
image-20261008172211459

4、旋转矩阵 Rotation Matrix

图像默认绕着原点进行旋转,并且默认都是逆时针旋转。根据下图两个特殊的点进行变换即可推算出这个旋转矩阵。
M_{rotation} = \begin{bmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{bmatrix}
image-20261008173536845

5、线性变换

若对任意向量 α,β∈V 与标量 k 满足:

  • T(α+β)=T(α)+T(β)
  • T(kα)=kT(α)

则称 T 为线性变换,上面提到的这几个变换都是线性变换,写成矩阵的形式就是 x'=Mx,其中这个矩阵需要和向量的维度相同,也就是二维向量对应 2×2 的矩阵,为什么特意强调这个呢?因为接下来需要提到一个概念。

(三)齐次坐标

1、为什么需要齐次坐标

因为平移变换不能用矩阵变换的形式表示出来:
\begin{bmatrix} x' \\ y' \end{bmatrix} = \begin{bmatrix} a & b \\ c & d \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix} + \begin{bmatrix} t_x \\ t_y \end{bmatrix}
image-20261008181353465

这并不是一个线性变换,需要额外加上一个矩阵才可以表示平移,但是我们不希望让平移变换变成一个特殊情况,因此引入了齐次坐标。

2、齐次坐标

通过增加一个维度可以将平移也写成矩阵相乘的形式。

\begin{bmatrix} x' \\ y' \\ w' \end{bmatrix} = \begin{bmatrix} 1 & 0 & t_x \\ 0 & 1 & t_y \\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} = \begin{bmatrix} x + t_x \\ y + t_y \\ 1 \end{bmatrix}

  • 2D Point = \begin{pmatrix} x, y, \boldsymbol{1} \end{pmatrix}^T
  • 2D Vector = \begin{pmatrix} x, y, \boldsymbol{0} \end{pmatrix}^T

这个 w 分量,点为 1 是因为受平移影响,向量为 0 则表示不受平移影响,即平移不变性。同时这个 w 分量在运算中也是有意义的,我们可以计算如下四种情况,注意结果中 w 的值,除了最后一个,其他都是有意义的。

  • vector + vector = vector
  • point - point = vector
  • point + vector = point
  • point + point = ?? (无意义)

对于最后一种情况,当 w \neq 0,齐次坐标 (x,y,w) 等价于二维点 \big(\frac{x}{w},\frac{y}{w}\big),即除以 w 归一化,使 w=1。

3、仿射变换

仿射变换是指在几何中,一个向量空间进行一次线性变换并接上一个平移,变换为另一个向量空间

  • 仿射映射 = 线性映射 + 平移

引入齐次坐标后,变换就变成了下方这样,其中最下面一行一般是固定的,左上的 abcd 则是线性变换,右上的 t 则是平移变换。
\begin{pmatrix} x' \\ y' \\ 1 \end{pmatrix} = \begin{pmatrix} a & b & t_x \\ c & d & t_y \\ 0 & 0 & 1 \end{pmatrix} \cdot \begin{pmatrix} x \\ y \\ 1 \end{pmatrix}

(四)逆变换

M^{-1} 既是矩阵代数意义上 M 的逆,也是几何变换意义上的逆变换,即反向操作。

image-20261008183007156

(五)复合变换

复合变换可以由多个简单变换组成,同时变换的顺序很重要,因为矩阵乘法不满足交换律。由于默认使用的是列向量,因此矩阵放左边,同时计算顺序是从右往左。

image-20261008183817686

由于矩阵乘法满足结合律,因此可以先计算前面的所有矩阵的复合矩阵,再和向量相乘也是可以的。

image-20261008183911103

(六)三维变换

三维和二维变换其实很像,只是多了一维而已。

  • 3D Point = \begin{pmatrix} x, y, z, \boldsymbol{1} \end{pmatrix}^T
  • 3D Vector = \begin{pmatrix} x, y, z, \boldsymbol{0} \end{pmatrix}^T

\begin{pmatrix} x' \\ y' \\ z' \\ 1 \end{pmatrix} = \begin{pmatrix} a & b & c & t_x \\ d & e & f & t_y \\ g & h & i & t_z \\ 0 & 0 & 0 & 1 \end{pmatrix} \cdot \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix}

四、Lecture 04 变换(续)

补充

正交矩阵:若矩阵的逆矩阵和转置矩阵一样,则该矩阵为正交矩阵。

(一)三维变换(续)

1、缩放矩阵
M_{scale} = \begin{bmatrix} s_{x} & 0 & 0 & 0 \\ 0 & s_{y} & 0 & 0 \\ 0 & 0 & s_{z} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}
2、平移矩阵
M_{translation} = \begin{bmatrix} 1 & 0 & 0 & t_{x} \\ 0 & 1 & 0 & t_{y} \\ 0 & 0 & 1 & t_{z} \\ 0 & 0 & 0 & 1 \end{bmatrix}
3、旋转矩阵

旋转矩阵是里面最复杂的了,当然推导和二维是类似的,就是固定某个轴不变,然后其他两个轴的变量进行旋转变换。

image-20261008225733776

当然你肯定会有疑惑,为什么绕 y 轴旋转的这个这么怪异,好像和其他两个是“相反”的?

这里就涉及到循环对称的性质了,就是各个轴由其他两个轴叉乘得来:x × y → z 、$ y × z → x$ 、z × x → y。注意y轴这里,它是 z 和 x 轴叉乘而来,从 y 轴逆向看去,x 是纵轴,z 才是横轴,即 z-x 坐标系,而非 x-z 坐标系,因此算出来才会“相反“。

当然直接理解的话其实就是第3列(z向量)是原本横轴的内容,并且从第3行开始填,即填入 (\cos\alpha, \sin\alpha) ,由于填写 \sin\alpha 时超出了第3行,所以填入了第1行。而第1列(x向量)是原本纵轴的内容,填入的是(-\sin\alpha, \cos\alpha),也从第3行开始填,最终绕 y 轴旋转的矩阵就是这么个”怪异“的答案。

image-20261008230223038

(二)3D旋转

1、欧拉角

是否可以用X/Y/Z单轴旋转矩阵组合出任意三维旋转?
R_{xyz}(\alpha,\beta,\gamma)=R_x(\alpha)\,R_y(\beta)\,R_z(\gamma)
这就是欧拉角(Euler angles),把任意三维旋转拆成先后三次绕坐标轴的单轴旋转相乘。比如对于飞行模拟器常用定义:

  • Roll:横滚,机翼上下翻转。
  • Pitch:俯仰,机头抬/低头。
  • Yaw:偏航,机头左右转向。

缺陷:欧拉角会出现万向锁(Gimbal Lock),丢失一个旋转自由度;并且插值容易抖动。

image-20261008232247029

2、罗德里格斯旋转公式

绕任意单位轴 \boldsymbol{n} 旋转角度 \alpha 的旋转矩阵:
\boldsymbol{R}(\boldsymbol{n},\alpha) =\cos(\alpha)\boldsymbol{I} +(1-\cos(\alpha))\boldsymbol{n}\boldsymbol{n}^T +\sin(\alpha) \underbrace{ \begin{pmatrix} 0 & -n_z & n_y \\ n_z & 0 & -n_x \\ -n_y & n_x & 0 \end{pmatrix} }_{\boldsymbol{N}}

推导繁琐,但思想比较简单。

3、四元数

四元数(Quaternion)的引入更多是为了旋转与旋转之间的插值,这里不过多讲解。

(三)观测变换

观测变换是该课程自己定义的一个概念,全称 Viewing transformation,它包含这两个部分:

  • 视图变换:View / Camera transformation
  • 投影变换:Projection transformation

下面就来讲解这两个变换。

(四)视图变换

1、概念

视图变换就是 View/Camera Transformation,要理解他就先以拍照为例,我们拍照分三步,也叫做MVP变换:

  • 找好场地、摆放物体。(模型变换 Model transformation)
  • 找一个合适角度放置相机。(视图变换 View transformation)
  • 按下快门拍照,把3D场景拍为2D图像。(投影变换 Projection transformation)

而视图变换就是第二步,负责摆放摄像机的,想要确定摄像机摆放情况,我们需要定义三个参数:

  • \vec{e}:相机位置(Position)
  • \hat{g}:相机视线/观察方向(Look-at / gaze direction)
  • \hat{t}:相机上方向(Up direction)

image-20261008234950882

这里有一个核心思想就是,既然摄像机拍摄的是相对运动,那么为何不让相机固定住呢?相机永远在原点,永远以Y轴为向上,相机永远看向-Z方向(约定俗成),之后将相机变换到上述固定位置,其他物体也进行一样的变换,效果是一样的。

为了计算这个变换矩阵,我们就需要解决这些问题:

  • 将相机位置 \vec{e} 平移到原点(平移)
  • 将视线方向 \hat{g} 旋转对齐到 -Z,将上方向 \hat{t} 旋转对齐到 Y,将右方向 (\hat{g}\times\hat{t}) 旋转对齐到 X(旋转)

这样我们就可以将问题转换成先应用平移矩阵,再应用旋转矩阵:
M_{view}=R_{view}\cdot T_{view}
image-20261008235558203

2、变换矩阵计算

(1)平移矩阵

这个很好理解,直接将相机移动到原点:
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}
(2)旋转矩阵

我们想要将这三个轴分别变成原点的 XYZ 轴,即:

  • 右轴 \hat{g}\times\hat{t} \rightarrow X
  • 上轴 \hat{t} \rightarrow Y
  • 视线 \hat{g} \rightarrow -Z

但是直接构造这个旋转很难,因此我们思考逆变换,即把标准坐标系 XYZ 转到相机自身坐标系,得出该矩阵后再求逆即可:

  • X \rightarrow (\hat{g}\times\hat{t})
  • Y \rightarrow \hat{t}
  • Z \rightarrow -\hat{g}

这样这个旋转矩阵就很容易得出来了,每一列代表目标轴的向量(比如第一列表示从X轴变成摄像机自身的X轴),这样一个变换就可以将标准坐标系 XYZ 转换成摄像机对应三个轴的坐标系。
R_{view}^{-1}= \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}
之后求其逆矩阵即可,并且由于旋转矩阵是正交矩阵,所以逆矩阵就是对应的转置矩阵:
R_{view}= \begin{bmatrix} x_{\hat{g}\times\hat{t}} & y_{\hat{g}\times\hat{t}} & z_{\hat{g}\times\hat{t}} & 0 \\ x_{t} & y_{t} & z_{t} & 0 \\ x_{-g} & y_{-g} & z_{-g} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}

(五)投影变换

1、概念

投影变换就是 Projection transformation,分为透视投影和正交投影,这个很好理解,其实就是透视投影有近大远小的一个关系,而正交投影则没有。

image-20261009002332826

2、正交投影

(1)概念

  • 特点:平行光线投射,物体大小不会随距离变化,没有透视近大远小效果,常用于工程制图、UI。
  • 简单理解:
    • 相机放在原点,看向 -Z,上方向为 Y。(看向 -Z 是约定)
    • 直接丢弃Z坐标,所有点沿平行于Z轴方向投影到 z=0 平面。
    • 投影得到的矩形的 x,y 映射到 [-1,1]^2 的二维标准化设备坐标。
  • 通用目标:把一个长方体视锥盒 [l,r]\times[b,t]\times[f,n] 映射到标准正则立方体(canonical cube) [-1,1]^3。前面六个字母就是六个方向的英文缩写。

(2)变换步骤

  • 平移 Translate:把长方体中心平移到坐标原点
  • 缩放 Scale:把长方体的长宽高缩放至2,刚好填满 [-1,1]^3

image-20261009103430535

和前面简单理解略有差别:不是先丢Z,而是先把整个3D长方体变换到标准立方体,之后再做裁剪,最后才丢弃Z。

(3)正交投影矩阵

变换顺序:先平移,后缩放
M_{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{Scale矩阵}} \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{Translate矩阵}}

  • 平移矩阵:把长方体中心点移动到原点。中心点坐标 (\frac{l+r}{2},\frac{b+t}{2},\frac{n+f}{2})
  • 缩放矩阵:将每个轴方向长度缩放到2。X轴总长度 r-l,缩放系数 \frac{2}{r-l};Y、Z同理。

3、透视投影

(1)概念

  • 特点:在计算机图形学、美术、人眼视觉系统中最常用,有近大远小的效果。
  • 目标:和正交投影一样,最终都需要将视锥体内的坐标映射到标准正则立方体 [-1,1]^3 中。

(2)前置知识

齐次坐标性质回顾:齐次向量 (x,y,z,1)、(kx,ky,kz,k),k\neq0、(xz,yz,z^2,z),z\neq0 都代表三维空间中同一个笛卡尔点 (x,y,z)。后面推导会用到。

(3)变换步骤

  • 挤压 Squish:把视锥体挤压成长方体,使之变得和正交投影的视锥体一样。
  • 执行正交投影 Orthographic Projection:用正交投影的方法再进行变换。

image-20261009115317268

(4)透视投影矩阵

我们主要关心的就是挤压的步骤,也就是求出把视锥体挤压成长方体的矩阵 M_{persp\rightarrow ortho}。

我们能确定的性质有这三条性质:

  • 近平面(n所在平面)的所有点变换后位置不变。
  • 远平面(f所在平面)的所有点变换后 z 值不变。
  • 远平面中心点 (0, 0, f) 变换后位置不变。

可能你有疑问:我知道 xy 会有一定程度缩放,但是中间那些点的 z 值不是固定不变的吗?

答案其实是:除了近平面和远平面的 z 不变外,中间这些点的 z 都会变,并且是非线性变化。为什么?不能让 z 变换后还是 z 吗,就是让所有点 z 值保持不变不行吗?

对于这个问题,这是我的个人理解:如果要让变换后 z 轴保持不变,这样的一个通用矩阵是找不到的,也就是矩阵会随 z 的变化而变化,而这应该就是不能让 z 保持不变的原因吧:我们希望找到一个通用的矩阵,所有情况都可以适用,而不是找一个会不停变化的矩阵,而使用通用矩阵的话只能让 z 变化了。

首先 x 和 y 的变化关系由相似三角形很容易得到:
y'=\frac{n}{z}y,\quad x'=\frac{n}{z}x
image-20261009220847251

然后是 z 的变化关系,上面我已经说了,z 是会变化的,但是至于怎么变化,目前还不知道,所以暂时设为 unknown。
\begin{pmatrix} x\\ y\\ z\\ 1 \end{pmatrix} \Rightarrow \begin{pmatrix} \frac{n}{z}x\\ \frac{n}{z}y\\ unknown\\ 1 \end{pmatrix}
由于这样矩阵会带有 z,也就是矩阵会随 z 变化,这是我们不希望看到的,因此我们这里需要用齐次坐标的性质消掉 z。即矩阵全部分量乘以同一个数,它们在三维空间中还是指的同一个点:
\begin{pmatrix} \frac{n}{z}x\\ \frac{n}{z}y\\ unknown\\ 1 \end{pmatrix} \overset{\times z}{==} \begin{pmatrix} nx\\ ny\\ unknown\\ z \end{pmatrix}
好的,现在这个变换就变成了:
M_{persp\rightarrow ortho} \begin{pmatrix}x\\y\\z\\1\end{pmatrix}= \begin{pmatrix}nx\\ny\\unknown\\z\end{pmatrix}
目前就能够确认矩阵的已知部分,除了第三行,其他肯定都能确认:
M_{persp\rightarrow ortho}= \begin{pmatrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ ? & ? & ? & ? \\ 0 & 0 & 1 & 0 \end{pmatrix}
现在的目标就是求出矩阵第三行,首先前两列一定是0,因为这个输出结果应该和 xy 无关,因此第三行的形式为:\boldsymbol{(0\ \ 0\ \ A\ \ B)}。为了求出 AB,我们需要取一些特殊位置来解,还记得上面的三条性质吗,这就是关键。

  • 近平面上所有点,变换后位置不变,近平面的 z = n,因此带入矩阵:

M_{persp\rightarrow ortho} \begin{pmatrix} x\\y\\n\\1 \end{pmatrix} = \begin{pmatrix} x\\y\\n\\1 \end{pmatrix} \overset{\times n}{==} \begin{pmatrix} nx\\ ny\\ n^2\\ n \end{pmatrix}

关注第三行,这样可以获得一个等式:
\begin{pmatrix} 0 & 0 & A & B \end{pmatrix} \begin{pmatrix} x\\y\\n\\1 \end{pmatrix}= An+B = n^2

  • 远平面中心点 (0, 0, f) 变换后位置不变。

M_{persp\rightarrow ortho} \begin{pmatrix} 0\\0\\f\\1 \end{pmatrix} = \begin{pmatrix} 0\\0\\f\\1 \end{pmatrix} \overset{\times f}{==} \begin{pmatrix} 0\\ 0\\ f^2\\ f \end{pmatrix}

关注第三行,这样又可以获取一个等式:
\begin{pmatrix} 0 & 0 & A & B \end{pmatrix} \begin{pmatrix} 0\\0\\f\\1 \end{pmatrix} = Af+B = f^2
两个等式结合,解得:
A = n+f,\quad B = -nf
因此这个挤压矩阵我们求出来是:
M_{persp\rightarrow ortho}= \begin{pmatrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ 0 & 0 & n+f & -nf \\ 0 & 0 & 1 & 0 \end{pmatrix}
挤压完成之后,继续执行正交投影 M_{ortho},就可以得到最终透视矩阵:
M_{persp}=M_{ortho}\cdot M_{persp\rightarrow ortho}

(六)思考

结尾闫令琪老师留了一个作业:挤压后的中间的 z 是偏离相机点还是靠近相机点,我算出来是远离相机的,这是计算过程:

image-20261009134344648

附录:课程作业环境搭建

1、准备

我使用的是VS2022+OpenCV+Eigen。需要准备如下三样东西:

2、配置Eigen

  • 右键解决方案,点击属性

image-20260405123133332

  • 选择C/C++ → 常规 → 附加包含目录,选中Eigen所在目录即可。

image-20260405123238084

  • 验证,在main中输入如下代码,如果没有报错并且正确打印两个矩阵的信息则说明配置正确。
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;

int main() {
	cout << "<========================>" << endl;
	Matrix<float, 3, 3>matrixA;
	matrixA.setZero();
	cout << matrixA << endl; 
	
	Matrix<float, 3, 3>matrixA1;
	matrixA1.setZero();
	cout << '\n' << matrixA1 << endl;
	cout << "<========================>" << endl;

	return 0;
}

注:作业里可能是 #include <eigen3/Eigen/Eigen> 的形式,这时候会报错,找不到头文件,解决办法有两个:

  • 删除头文件前面的 ”eigen3/“ 路径。
  • 调整 ”附加包含目录“,先将 eigen 所在文件夹命名为 eigen3,然后这个目录选取其父目录即可。

3、配置OpenCV

  • 下载好后,先配置环境变量,将opencv\build\x64\vc16\bin这个路径添加到环境变量的Path中

  • 右键解决方案,点击属性,选择VC++目录,配置包含目录和库目录

    • 包含目录:opencv\build\include
    • 库目录:opencv\build\x64\vc16\lib

image-20260405124419459

  • 配置附加依赖项,在刚才的lib目录下找到这个库文件,复制名字

image-20260405124804776

  • 然后在 链接器 → 输入 → 附加依赖项 中将刚才复制的名字粘贴进去

image-20260405124935762

  • 之后运行如下程序进行测试,如果能正常打开图片代表成功
#include <opencv2/opencv.hpp>
using namespace cv;
int main() {
	Mat img = imread("你的图片路径");
	imshow("test", img);
	waitKey(0);
	return 0;
}