速成 · 计算机图形学

计算机图形学不是“会调用 OpenGL 就行”,它真正研究的是:怎样把对三维世界的描述,稳定、高效地变成二维屏幕上的像素。

课件的 11 讲可以压成一条流水线:

计算机图形学渲染流水线

如果只剩几个小时,先把下面六个问题想明白。

一、一个点怎样走到屏幕上

齐次坐标把平移也纳入矩阵乘法。列向量约定下,一个物体坐标点依次经过

pclip=PVMpobject.\mathbf p_{clip}=PVM\mathbf p_{object}.
  • MM:把局部模型摆进世界。
  • VV:把世界改写到以相机为原点的坐标系。
  • PP:把可见空间映到裁剪空间。

随后做透视除法

pndc=(xcwc,ycwc,zcwc),\mathbf p_{ndc} =\left( \frac{x_c}{w_c}, \frac{y_c}{w_c}, \frac{z_c}{w_c} \right),

再由视口变换把 [−1,1]2[-1,1]^2 映到屏幕像素。矩阵乘法不可交换,所以代码里矩阵写反会直接得到另一种几何效果。

正交投影没有“近大远小”;透视投影让远处物体因除以深度而缩小。法线不能一律乘模型矩阵:非均匀缩放下,应使用

n′=(M−1)Tn.\mathbf n'=(M^{-1})^T\mathbf n.

二、连续三角形怎样变成离散像素

裁剪先去掉视锥外的部分。线段可用 Cohen–Sutherland 区域码快速接受、拒绝或求交;多边形可依次对四条裁剪边执行 Sutherland–Hodgman。

光栅化则问:哪些像素中心落在三角形内?对三个有向边函数同号即可判内。只扫描三角形包围盒,并增量更新边函数,比逐像素重新求直线方程更快。

三角形顶点属性用重心坐标插值:

p=αa+βb+γc,α+β+γ=1.\mathbf p=\alpha\mathbf a+\beta\mathbf b+\gamma\mathbf c, \qquad \alpha+\beta+\gamma=1.

颜色、深度、法线和纹理坐标都可沿用这套权重。但透视投影后,纹理坐标不能直接做屏幕空间线性插值,而要先插值 u/wu/w 与 1/w1/w,最后相除。

锯齿、摩尔纹和错误运动感都是采样不足的不同表现。空间反走样的核心不是“把边缘抹糊”,而是先低通、再采样。最直观的实现是每像素多次采样后取平均。

三、谁挡住谁

背面剔除可先删掉朝向远离相机的三角形,但不能解决物体间遮挡。Painter 算法按远到近画,遇到相交或循环遮挡会失效;BSP 能预先建立空间顺序,但动态场景不方便。

实时光栅化通常使用 Z-buffer:

  1. 深度缓冲初始化为最远值。
  2. 每个片元算出插值深度。
  3. 只有比当前记录更近的片元才能写颜色,并更新深度。

它把全局排序改成了每像素的局部比较,复杂度近似与产生的片元数成正比。

四、为什么同一个面会有明暗

课件采用局部 Blinn–Phong 模型:

L=La+kdImax⁡(0,n⋅l)+ksImax⁡(0,n⋅h)p.L=L_a+ k_d I\max(0,\mathbf n\cdot\mathbf l) + k_s I\max(0,\mathbf n\cdot\mathbf h)^p.

n\mathbf n 是法线,l\mathbf l 指向光源,h\mathbf h 是光线与视线的半程向量。环境项防止背光面全黑;漫反射决定大体明暗;镜面项形成高光,指数 pp 越大,高光越尖。

“模型”和“计算频率”要分开:

  • Flat:每个三角形算一次,棱角明显。
  • Gouraud:每顶点算光照,再插值颜色,可能漏掉小高光。
  • Phong shading:插值法线,再逐片元算光照,最平滑。

五、纹理和阴影在补什么信息

纹理映射为表面建立 (u,v)(u,v) 坐标,再从纹理图反查颜色。放大时可用双线性插值;缩小时一个像素覆盖很多纹素,单点采样会闪烁。Mipmap 预先存储逐级低通降采样图,按像素足迹选择层级;三线性插值再在相邻两级间过渡。各向异性过滤用于细长而倾斜的像素足迹。

Bump Mapping 不增加几何,只扰动法线,因此轮廓不会变;Displacement Mapping 真正移动表面,需要足够细的网格。

Shadow Mapping 做两遍渲染:

  1. 从光源看场景,记录最近深度。
  2. 从相机看场景,把片元投回光源坐标,比较它与 Shadow Map 中的深度。

深度误差会产生自阴影斑点,需要 bias;分辨率不足造成锯齿,可用 Percentage Closer Filtering 多点比较后求平均。

六、曲线、曲面与网格怎样表示形状

几何表示没有绝对最优。隐式曲面 f(x,y,z)=0f(x,y,z)=0 容易做内外判断和布尔运算,却不易直接枚举表面点;显式参数曲面 p(u,v)\mathbf p(u,v) 容易采样和绘制,却未必容易判断内外。点云、三角网格、 Bezier 曲线和细分曲面都是显式表示。

三次 Bezier 曲线由四个控制点决定:

B(t)=(1−t)3P0+3(1−t)2tP1+3(1−t)t2P2+t3P3.\mathbf B(t)= (1-t)^3\mathbf P_0+ 3(1-t)^2t\mathbf P_1+ 3(1-t)t^2\mathbf P_2+ t^3\mathbf P_3.

它插值首尾点、位于控制点凸包内,并具有仿射不变性。复杂形状通常拼接低次曲线;位置相接是 C0C^0,一阶导数也相接才是 C1C^1。Bezier 曲面是两个参数方向上的张量积。

三角网格把几何位置和连接关系分开。半边结构把一条无向边拆成方向相反的两条半边,用 twin、next、face 等指针把邻域查询降到局部操作。Loop 细分提升三角网格分辨率;Quadric Error Metric 通过边折叠并累计到邻接平面的平方距离来做简化。

最后记住的做题顺序

  1. 先标清当前坐标系和矩阵作用方向。
  2. 再分清顶点阶段、光栅化阶段和片元阶段。
  3. 插值题先写重心坐标;有透视就检查是否需要除以 ww。
  4. 可见性题先区分背面剔除、深度测试与阴影,它们解决的是三个不同问题。
  5. 光照题先画出 n,l,v,h\mathbf n,\mathbf l,\mathbf v,\mathbf h,再代公式。
  6. 网格题先区分几何数据和连接关系,再讨论局部编辑或细分。

这条主线走通后,11 讲课件就不再是互不相干的算法,而是同一张图形流水线上的不同工位。

评论