图形学是什么
计算机图形学 Computer Graphics 研究如何用计算机生成、表示和处理视觉内容。它的输入通常是一个场景描述:几何形状、材质、光源、相机以及随时间变化的运动;输出可以是一张图像,也可以是一段动画。把场景中的几何、光照和材质综合成相机能够看到的图像,这个过程通常称为渲染 Rendering 。
屏幕上的图像是二维的,但它往往来自三维场景。三维模型决定物体在哪里、长什么样,材质决定它如何与光作用,光源决定能量从哪里来,相机决定从哪个位置观察。图形学的任务是把这些因素放进同一套可计算的模型中,再在有限时间内得到稳定的图像。
图中左侧的两个观察体积分别对应透视投影和正交投影。透视投影的视线从相机一点发散,远处截面更大,物体会近大远小;正交投影的投影线彼此平行,物体大小不随深度变化。右侧把连续的三角形轮廓叠到像素网格上,说明投影先确定连续位置,光栅化再判断哪些离散像素被覆盖。斜边呈阶梯状,是连续几何被离散采样后的结果。
四条主线
课程把图形学按问题组织成四条主线。
光栅化 Rasterization :把连续的几何图元投影到屏幕,再离散成像素或采样点。它是实时渲染最常用的基础方法。
几何 Geometry :研究曲线、曲面、网格和复杂形体的表示、编辑、细分与简化。
光传输 Light Transport :计算光的发射、反射、折射和散射,求出最终到达相机的光。光线追踪和路径追踪属于这条主线。
动画与模拟 Animation and Simulation :描述物体随时间的位置、姿态和形变,并根据力学或其他物理规律模拟布料、刚体、流体和粒子。
光栅化通常速度快,适合游戏和交互式应用;光线追踪能够更自然地处理阴影、反射和间接光,但计算成本通常更高。实时图形学通常以每秒约 30 帧作为直观门槛,离线渲染则可以用更长时间换取更高质量。实时光线追踪试图缩小两者之间的差距,这正是图形学中常见的速度与质量取舍。
学科边界
可以把几个方向画成不同的映射关系:
图形学通常从模型、材质和光源出发生成图像,即 model → image ;
计算机视觉通常从图像推断物体、几何和语义,即 image → model ;
图像处理主要在已有二维图像之间做增强、变换和重建,即 image → image ;
几何建模和物理模拟可以在没有图像输入的情况下,从模型生成另一个模型,即 model → model 。
真实研究中的边界并不绝对。计算摄影会改变成像方式,深度学习也可能同时出现在视觉、图像处理和图形学中;增强现实系统往往先用视觉识别现实,再把图形学内容叠加回画面。这里的区分用于理解问题的输入和输出,不是给研究领域划一条不可跨越的线。
OpenGL、DirectX、Vulkan 和 Metal 是应用程序与图形硬件之间的 API,建模软件和游戏引擎是内容创作或运行工具。它们建立在图形学理论上,但 API 的调用方式不等于图形学本身。理解投影、光栅化、光照和可见性的原理之后,再学习某一种 API 会容易得多。
向量
点 Point 表示空间中的绝对位置,向量 Vector 表示位移、方向和长度。数学中常称向量,物理中也常称矢量。给定点 A A A 和 B B B ,从 A A A 指向 B B B 的位移向量是
A B → = B − A . \overrightarrow{AB}=B-A.
A B = B − A .
向量整体平移后,只要方向和长度不变,仍表示同一个向量。它没有必须固定的绝对起点。向量通常写作带箭头的字母 a ⃗ \vec a a ,印刷体中也常写成粗体 a \mathbf a a 。
点和向量的运算需要遵守类型关系。两个点相减得到从一个点指向另一个点的向量;点加向量得到新的点;两个向量可以相加,但两个点相加没有自然的几何意义。这个区分在齐次坐标中还会进一步编码成末位的 1 和 0。
三维列向量可以写成
v = ( x y z ) . \mathbf v=\begin{pmatrix}x\\y\\z\end{pmatrix}.
v = x y z .
图形学默认把向量写成列向量。转置 T T T 把行和列互换,例如 ( x , y , z ) T (x,y,z)^T ( x , y , z ) T 是横排坐标写法;行向量也可以使用,但后续矩阵乘法必须始终遵守同一约定。
向量运算
向量加法有两种等价的几何解释。平行四边形法则把两个向量的起点放在同一点,以它们为邻边作平行四边形,对角线就是和向量;三角形法则把第二个向量的起点接到第一个向量的终点,首尾相接可以自然推广到任意多个向量。代数上,向量加法就是对应分量相加。
标量乘法按分量缩放向量。标量为正时方向不变,为负时方向反向,绝对值决定长度缩放;标量为零得到零向量。减法可以写成加上相反向量。
三维向量的欧氏模长是
∥ v ∥ = x 2 + y 2 + z 2 . \lVert\mathbf v\rVert=\sqrt{x^2+y^2+z^2}.
∥ v ∥ = x 2 + y 2 + z 2 .
在二维中,水平 4 格、竖直 3 格的向量长度是 4 2 + 3 2 = 5 \sqrt{4^2+3^2}=5 4 2 + 3 2 = 5 。模长为 1 的向量称为单位向量。任意非零向量都可以归一化:
v ^ = v ∥ v ∥ . \hat{\mathbf v}=\frac{\mathbf v}{\lVert\mathbf v\rVert}.
v ^ = ∥ v ∥ v .
零向量没有方向,不能归一化。法线是垂直于表面切平面的方向,切向量沿表面延伸;在光照、相机和光源计算中,这些方向通常先归一化。
在笛卡尔坐标系中,若基向量 e x , e y \mathbf e_x,\mathbf e_y e x , e y 是互相垂直的单位向量,则
v = x e x + y e y . \mathbf v=x\mathbf e_x+y\mathbf e_y.
v = x e x + y e y .
模长写成各分量平方和的平方根,依赖于坐标基的正交性和单位长度。若基向量不是正交单位基,就不能直接套用这个公式。
坐标系本身也不是唯一的:局部坐标描述模型,世界坐标描述场景,相机坐标描述观察,规范化设备坐标和屏幕坐标描述投影后的结果。不同坐标系之间的换算会在几何变换一节中统一写成矩阵乘法。
点积
点积 Dot Product 把两个向量映射为一个标量:
a ⋅ b = ∥ a ∥ ∥ b ∥ cos θ = a x b x + a y b y + a z b z . \mathbf a\cdot\mathbf b
=\lVert\mathbf a\rVert\lVert\mathbf b\rVert\cos\theta
=a_xb_x+a_yb_y+a_zb_z.
a ⋅ b = ∥ a ∥ ∥ b ∥ cos θ = a x b x + a y b y + a z b z .
其中 θ \theta θ 是两个向量的夹角。若两个向量都是单位向量,点积就是 cos θ \cos\theta cos θ ,因此可以用
cos θ = a ⋅ b ∥ a ∥ ∥ b ∥ \cos\theta=\frac{\mathbf a\cdot\mathbf b}
{\lVert\mathbf a\rVert\lVert\mathbf b\rVert}
cos θ = ∥ a ∥ ∥ b ∥ a ⋅ b
求夹角。点积大于 0 表示夹角小于 90 ∘ 90^\circ 9 0 ∘ ,等于 0 表示垂直,小于 0 表示夹角大于 90 ∘ 90^\circ 9 0 ∘ 。对于单位向量,点积从 1 到 −1 连续表示方向的接近程度。判断正负时,分界不是向量 a \mathbf a a 所在的直线,而是经过原点且垂直于 a \mathbf a a 的直线(二维)或平面(三维)。
点积满足交换律、分配律和标量相容性:
a ⋅ b = b ⋅ a , \mathbf a\cdot\mathbf b=\mathbf b\cdot\mathbf a,
a ⋅ b = b ⋅ a ,
a ⋅ ( b + c ) = ( a ⋅ b ) + ( a ⋅ c ) , \mathbf a\cdot(\mathbf b+\mathbf c)
=(\mathbf a\cdot\mathbf b)+(\mathbf a\cdot\mathbf c),
a ⋅ ( b + c ) = ( a ⋅ b ) + ( a ⋅ c ) ,
( k a ) ⋅ b = k ( a ⋅ b ) . (k\mathbf a)\cdot\mathbf b=k(\mathbf a\cdot\mathbf b).
( k a ) ⋅ b = k ( a ⋅ b ) .
点积没有通常意义下的结合律,因为第一次点积已经得到标量;( a ⋅ b ) c (\mathbf a\cdot\mathbf b)\mathbf c ( a ⋅ b ) c 与 a ( b ⋅ c ) \mathbf a(\mathbf b\cdot\mathbf c) a ( b ⋅ c ) 一般是不同方向的向量。
在光照中,法线、光线方向和观察方向通常都先归一化。这样 n ⋅ l \mathbf n\cdot\mathbf l n ⋅ l 直接表示入射角余弦,n ⋅ h \mathbf n\cdot\mathbf h n ⋅ h 可以表示观察方向是否接近高光方向。若忘记归一化,点积会同时混入向量长度,数值就不能只解释成方向接近程度。
投影
向量 a \mathbf a a 在非零参考向量 b \mathbf b b 上的投影向量为
proj b a = a ⋅ b b ⋅ b b . \operatorname{proj}_{\mathbf b}\mathbf a
=\frac{\mathbf a\cdot\mathbf b}{\mathbf b\cdot\mathbf b}\mathbf b.
proj b a = b ⋅ b a ⋅ b b .
若 b ^ \hat{\mathbf b} b ^ 是单位向量,公式简化为
proj b ^ a = ( a ⋅ b ^ ) b ^ . \operatorname{proj}_{\hat{\mathbf b}}\mathbf a
=(\mathbf a\cdot\hat{\mathbf b})\hat{\mathbf b}.
proj b ^ a = ( a ⋅ b ^ ) b ^ .
投影长度带符号:夹角为锐角时为正,钝角时为负。把 a \mathbf a a 分解成平行和垂直两部分:
a = a ∥ + a ⊥ , a ⊥ = a − a ∥ . \mathbf a=\mathbf a_{\parallel}+\mathbf a_{\perp},\qquad
\mathbf a_{\perp}=\mathbf a-\mathbf a_{\parallel}.
a = a ∥ + a ⊥ , a ⊥ = a − a ∥ .
在漫反射中,光线方向和法线方向的点积就是入射余弦。光线位于表面背面时点积为负,实际单面模型通常使用 max ( 0 , n ⋅ l ) \max(0,\mathbf n\cdot\mathbf l) max ( 0 , n ⋅ l ) 。
图中黑色向量 a \mathbf a a 是参考方向,向量 b \mathbf b b 被投影到 a \mathbf a a 所在直线上;红色箭头表示 b \mathbf b b 的平行分量,投影长度由直角三角形给出。图中的 b ⊥ \mathbf b_\perp b ⊥ 是“投影到参考方向”的标记,几何上对应平行分量,并不是与 a \mathbf a a 垂直的残差。参考方向反过来时,有符号投影也会反向。保留符号对于坐标分解和光照背面判断都很重要。
叉积
叉积 Cross Product 输出一个同时垂直于两个输入向量的向量:
a × b = ( a y b z − a z b y a z b x − a x b z a x b y − a y b x ) . \mathbf a\times\mathbf b=
\begin{pmatrix}
a_yb_z-a_zb_y\\
a_zb_x-a_xb_z\\
a_xb_y-a_yb_x
\end{pmatrix}.
a × b = a y b z − a z b y a z b x − a x b z a x b y − a y b x .
它的模长为
∥ a × b ∥ = ∥ a ∥ ∥ b ∥ sin θ , \lVert\mathbf a\times\mathbf b\rVert
=\lVert\mathbf a\rVert\lVert\mathbf b\rVert\sin\theta,
∥ a × b ∥ = ∥ a ∥ ∥ b ∥ sin θ ,
等于以 a , b \mathbf a,\mathbf b a , b 为邻边的平行四边形面积。方向由右手定则确定。交换顺序会变号,自身叉积是零向量:
a × b = − ( b × a ) , a × a = 0. \mathbf a\times\mathbf b=-(\mathbf b\times\mathbf a),
\qquad \mathbf a\times\mathbf a=\mathbf0.
a × b = − ( b × a ) , a × a = 0 .
叉积满足分配律和标量相容性,但不满足结合律。叉积还可以写成对偶矩阵:
[ a ] × = ( 0 − a z a y a z 0 − a x − a y a x 0 ) , a × b = [ a ] × b . [\mathbf a]_\times=
\begin{pmatrix}
0&-a_z&a_y\\
a_z&0&-a_x\\
-a_y&a_x&0
\end{pmatrix},
\qquad
\mathbf a\times\mathbf b=[\mathbf a]_\times\mathbf b.
[ a ] × = 0 a z − a y − a z 0 a x a y − a x 0 , a × b = [ a ] × b .
在二维平面中,把向量嵌入 z = 0 z=0 z = 0 平面,叉积只剩 z 分量:
( ( B − A ) × ( P − A ) ) z = ( B x − A x ) ( P y − A y ) − ( B y − A y ) ( P x − A x ) . ((B-A)\times(P-A))_z
=(B_x-A_x)(P_y-A_y)-(B_y-A_y)(P_x-A_x).
(( B − A ) × ( P − A ) ) z = ( B x − A x ) ( P y − A y ) − ( B y − A y ) ( P x − A x ) .
这个有符号面积的正负判断点 P P P 在有向边 A B AB A B 的左侧还是右侧。对于逆时针三角形 A B C ABC A BC ,依次计算 A B / A P AB/AP A B / A P 、B C / B P BC/BP BC / BP 、C A / C P CA/CP C A / CP 的叉积;三个结果都非负时,点在闭三角形内部。顺时针三角形对应三个结果都非正。落在边界上时,工程实现必须统一约定,否则相邻三角形可能重复着色或留下裂缝,硬件常用左上规则处理。
图的左侧把两个向量放在 x y xy x y 平面中,叉积沿垂直平面的 z 方向;交换向量顺序会让 z 分量反向。右侧用三角形 A B C ABC A BC 和测试点 P P P 展示三条有向边的内测:逆时针绕序下,若 P P P 对三条边都落在同一侧,就位于三角形内部。
坐标框架
三维标准正交基由三个长度为 1、两两垂直的向量 u , v , w \mathbf u,\mathbf v,\mathbf w u , v , w 构成:
∥ u ∥ = ∥ v ∥ = ∥ w ∥ = 1 , \lVert\mathbf u\rVert=\lVert\mathbf v\rVert=\lVert\mathbf w\rVert=1,
∥ u ∥ = ∥ v ∥ = ∥ w ∥ = 1 ,
u ⋅ v = v ⋅ w = w ⋅ u = 0. \mathbf u\cdot\mathbf v=\mathbf v\cdot\mathbf w
=\mathbf w\cdot\mathbf u=0.
u ⋅ v = v ⋅ w = w ⋅ u = 0.
若 u × v = w \mathbf u\times\mathbf v=\mathbf w u × v = w ,则这是右手坐标系。任意向量 p \mathbf p p 都可以按投影分解:
p = ( p ⋅ u ) u + ( p ⋅ v ) v + ( p ⋅ w ) w . \mathbf p=(\mathbf p\cdot\mathbf u)\mathbf u
+(\mathbf p\cdot\mathbf v)\mathbf v
+(\mathbf p\cdot\mathbf w)\mathbf w.
p = ( p ⋅ u ) u + ( p ⋅ v ) v + ( p ⋅ w ) w .
图形管线会使用多套坐标系:物体自身的局部坐标、描述整个场景的世界坐标、相机坐标、规范化设备坐标和屏幕坐标。坐标系之间的变换必须明确轴向、手性、深度范围和矩阵乘法约定。OpenGL 传统相机/世界约定采用右手坐标;其他 API 或资产工具也可能采用左手坐标,不能把某一个 API 名称直接等同于左手系。
矩阵
矩阵 Matrix 是按行列排布的数表。若 A A A 是 m × n m\times n m × n 、B B B 是 n × p n\times p n × p ,则 A B AB A B 存在且为 m × p m\times p m × p 。结果第 i , j i,j i , j 个元素是 A A A 第 i i i 行与 B B B 第 j j j 列的点积:
( A B ) i j = ∑ k = 1 n A i k B k j . (AB)_{ij}=\sum_{k=1}^{n}A_{ik}B_{kj}.
( A B ) ij = k = 1 ∑ n A ik B kj .
例如 3 × 2 3\times2 3 × 2 矩阵乘 2 × 4 2\times4 2 × 4 矩阵得到 3 × 4 3\times4 3 × 4 矩阵。课程例子中,第二行与第四列的点积为 5 × 4 + 2 × 3 = 26 5\times4+2\times3=26 5 × 4 + 2 × 3 = 26 ,第三行与第一列的点积为 0 × 3 + 4 × 2 = 8 0\times3+4\times2=8 0 × 3 + 4 × 2 = 8 。
矩阵乘法一般不满足交换律:A B ≠ B A AB\ne BA A B = B A ;但满足结合律和分配律。结合律允许把一长串变换先合成为一个矩阵,非交换性则要求严格保留变换顺序。
矩阵与列向量相乘时,矩阵写在左侧。关于 y 轴反射的二维矩阵是
( x ′ y ′ ) = ( − 1 0 0 1 ) ( x y ) , \begin{pmatrix}x'\\y'\end{pmatrix}
=
\begin{pmatrix}-1&0\\0&1\end{pmatrix}
\begin{pmatrix}x\\y\end{pmatrix},
( x ′ y ′ ) = ( − 1 0 0 1 ) ( x y ) ,
即 x ′ = − x , y ′ = y x'=-x,y'=y x ′ = − x , y ′ = y 。单位矩阵 I I I 是乘法的中性元,逆矩阵满足
A A − 1 = A − 1 A = I , ( A B ) − 1 = B − 1 A − 1 . AA^{-1}=A^{-1}A=I,
\qquad (AB)^{-1}=B^{-1}A^{-1}.
A A − 1 = A − 1 A = I , ( A B ) − 1 = B − 1 A − 1 .
转置交换行列,且
( A B ) T = B T A T . (AB)^T=B^TA^T.
( A B ) T = B T A T .
若矩阵满足 R − 1 = R T R^{-1}=R^T R − 1 = R T ,它称为正交矩阵。旋转矩阵属于正交矩阵,因此旋转的逆可以直接用转置得到。点积也能写成矩阵乘法:
a ⋅ b = a T b . \mathbf a\cdot\mathbf b=\mathbf a^T\mathbf b.
a ⋅ b = a T b .
方阵的行列式描述有向面积或体积的缩放。绝对值表示缩放倍率,符号表示定向是否翻转;行列式为 0 时至少有一个方向坍缩,矩阵没有逆。行列式满足
det ( A B ) = det ( A ) det ( B ) , \det(AB)=\det(A)\det(B),
det ( A B ) = det ( A ) det ( B ) ,
因此复合变换的总体积倍率等于各步倍率相乘。
矩阵和向量为坐标、变换和相机运动提供了统一表达。下一讲将从这些基本操作出发,建立二维和三维的几何变换。