计算机图形学

第七章(1) 隐面消除

思考:如何让计算机正确画出三维场景?

想象一下,我们正在玩一款3D游戏或者观看一部动画电影。

计算机是如何知道哪些物体在前,哪些物体在后?

如果把远的物体画在了近的物体前面,会发生什么?

这就是我们今天要解决的核心问题:隐面消除。

课程目标

在本节课结束后,你将能够:

  • 解释 为什么隐面消除在三维渲染中至关重要
  • 描述 背面剔除算法的基本原理和局限性
  • 比较 画家算法和Z-Buffer算法的思路、优缺点
  • 分析 Z-Buffer算法在现代图形硬件中成为主流的原因

课前思考 (前测)

在渲染一个三维场景时,如果两个不透明的物体在屏幕上占据了相同的像素位置,我们应该显示哪个物体的颜色?

  • A. 两个物体的颜色混合
  • B. 距离相机更远的那个物体
  • C. 距离相机更近的那个物体
  • D. 随机选择一个

再看渲染

流水线全景图

为什么需要隐面消除?

在三维场景中,物体之间存在遮挡关系。我们需要决定哪些部分是可见的,哪些是被遮挡的。

隐面消除 (Hidden Surface Removal, HSR),也称为可见面判别 (Visible Surface Determination),是图形学中的核心问题之一。

隐面消除示意

背面剔除(Back-face Culling)

核心思想: 对于封闭的凸多面体,背向观察者的面是不可见的,可以直接丢弃,不进行后续的渲染计算。

背面

背面剔除(Back-face Culling)

顶点缠绕顺序

背面剔除 (Back-face Culling)

判定方法: 利用多边形的法向量 $\vec{n}$ 和 视线向量 $\vec{v}$ (从物体指向相机)。

  • 如果 $\vec{v} \cdot \vec{n} > 0$,则该面朝向观察者(假设视线方向为观察方向,法线朝外)。
  • 如果 $\vec{v} \cdot \vec{n} < 0$,则表示背面

注意: 上述方法仅适用于凸多边形,对于凹多边形,可能存在多个法线方向,无法使用上述方法进行判断

背面剔除的局限性

  • 仅适用于封闭多面体。
  • 对于凹多面体,或者相互遮挡的多个物体,仅靠背面剔除是不够的。
  • 它通常作为一种预处理手段,可以剔除约50%的面片,提高效率。

对象空间方法

  • 对物体两两进行遮挡性测试
  • 最差情况下,对$n$个多边形,其复杂度:$O(n^2)$
遮挡排序

画家算法

基本思想: 像油画画家一样,先画背景(远的),再画前景(近的)。遵循从后往前的顺序绘制多边形,保证后方的多边形被前方的多边形遮挡

步骤:

  1. 将场景中所有多边形按深度(Z值)进行排序
  2. 从最远的多边形开始,依次向屏幕绘制

优点: 简单,不需要额外的硬件支持

画家算法

深度排序

画家算法要求对多边形按深度进行排序

  • 排序算法复杂度为$O(n\log{n})$
  • 存在一些三角形并不完全位于某些三角形前或完全位于某些三角形后,存在简单和复杂情况
  • 先对简单情况进行排序,后处理复杂情况
画家算法深度排序

深度排序简单情形

如果多边形A位于所有的多边形后,可直接绘制该多边形

深度排序简单情形A

若多边形在$Z$方向上有重叠,但在$X$和$Y$方向上都没重叠,可以在几个方向上分别独立绘制

深度排序简单情形B

深度排序复杂情况

多边形可能相交,或者深度范围重叠,难以简单排序

所有方向上均有重叠,在一个方向上完全位于另一个的一侧

深度排序复杂情形A

循环重叠(Cyclic Overlap)

深度排序复杂情形B

穿透重叠(Penetration)

深度排序复杂情形C

解决方法:需要分割多边形,增加计算复杂度

图像空间方法

  • 对成像平面的每个像素,查看每条投影线,即对$m\times n$的帧缓存,总共有$mn$个,分别找到距离最近的$k$个多边形
  • 其计算复杂度为$O(mnk)$
  • 可采用光线跟踪算法、Z-Buffer算法等
图像空间方法

深度缓存算法

这是现代图形硬件(GPU)的标准做法

核心思想: 在像素级别进行深度比较

需要两个缓冲区:

  • 帧缓存 (Frame Buffer): 存储颜色值 (RGB)
  • 深度缓存 (Z-Buffer): 存储每个像素当前的最小深度值 (Z)
深度缓存

Z-Buffer 算法步骤

z-buffer算法步骤
  1. 初始化: 将帧缓存置为背景色,将深度缓存置为无穷远(最大深度)。
  2. 遍历: 对场景中的每个多边形,进行光栅化。
  3. 测试: 对于多边形覆盖的每个像素 $(x, y)$,计算其深度值 $z$。
  4. 比较与更新:
    
    if (z < ZBuffer[x][y]) {
        ZBuffer[x][y] = z;       // 更新深度
        FrameBuffer[x][y] = color; // 更新颜色
    }
                                

Z-buffer算法举例

Z-Buffer 算法交互演示

Z-Buffer 的优缺点

优点

  • 简单,易于硬件实现。
  • 不需要对物体排序。
  • 处理循环遮挡毫无压力。
  • 复杂度与物体数量成线性关系。

缺点

  • 需要额外的内存(显存)存储 Z-Buffer。
  • Z-Fighting: 当两个面片深度非常接近时,由于精度限制,可能出现闪烁。
  • 无法处理透明物体(透明物体需要排序后由远及近绘制)。

随堂测验 (后测)

问题:以下哪种隐面消除算法最容易受到“循环遮挡”问题的困扰?

  • A. Z-Buffer 算法
  • B. 画家算法
  • C. 背面剔除
  • D. 光线追踪

总结

  • 隐面消除是三维渲染必不可少的步骤。
  • 背面剔除是一种简单的预处理优化。
  • 画家算法在物体空间排序,但难以处理复杂遮挡。
  • Z-Buffer算法在图像空间(像素级)操作,是目前硬件渲染的主流选择。