三角形特性与消隐算法
这篇文章主要是对前面知识点的补充,主要围绕两点展开:一是三角形的数学特性,解释为什么图形学中所有场景和模型都由无数个三角形拼接而成;二是消隐算法,即在一个三维场景中判断哪些物体或面被遮挡,只把看得见的部分渲染到屏幕上。
三角形特性
1. 它是最基础的多边形(最少顶点数)
1 个顶点是点,2 个顶点是线,3 个顶点才能构成面。使用三角形意味着用最少的数据量来描述一个面——如果使用四边形或五边形,传输和存储的顶点数据和拓扑关系会变得复杂得多。
2. 三角形必定是”共面的”(保证绝对平坦)
三点确定一个平面。无论你怎么在三维空间中移动三角形的三个顶点,它们永远都在同一个平面上。如果使用四边形,很可能出现某一个顶点和其他三个顶点不共面的情况,导致渲染出现裂缝或折叠。
3. 三角形一定是凸多边形(Convex)
三角形的内角和是
凸多边形使光栅化、裁剪以及填充等操作简单高效。GPU 只需要用重心坐标判断就能快速知道一个像素在不在三角形里面。如果是凹多边形,判断像素是否在其内部的计算量会急剧上升。
4. 重心坐标插值(Barycentric Coordinates)非常完美
在后续要介绍的着色中,我们需要对三角形面进行涂颜色、贴纹理、算光照等操作。如果对三角形内部每一个像素都执行这一整套计算,开销会非常大。因此我们一般只对顶点进行计算,而对三角形内部的像素使用插值。
三角形拥有一种非常优雅的数学工具——重心坐标插值。给定三角形内部任意一点
利用这个权重
5. 任何复杂的多边形都可以拆分成三角形(万物皆可三角化)
无论是四边形、五边形,还是复杂的曲面(如 NURBS、贝塞尔曲面),在数学上都可以非常轻松地被三角化。由此,GPU 可以专注于优化三角形渲染这一种图元,用最简单的流水线处理最大的吞吐量。
图形学选择三角形,是数学上的必然(共面、凸多边形、完美插值)与硬件设计上的最优解的统一。
前面我们讲了三维空间内的投影,所有物体最终都会被渲染在二维屏幕上。这便产生了一个问题:如果不同物体上的两个点最终映射到屏幕的同一坐标,该渲染哪一个?答案是根据它们的深度来判断——深度浅(离相机近)的像素应该覆盖深度深(离相机远)的像素。
消隐算法正是为了解决这一问题而设计的。图形学中的消隐算法主要分为两大类:
| 类别 | 处理对象 | 核心问题 |
|---|---|---|
| 图像空间级(Image-space) | 屏幕像素 | “对于屏幕上的像素 |
| 空间物体级(Object-space) | 三维几何体 | “在三维空间中,物体 |
图像空间消隐算法
深度缓冲算法(Z-Buffer / Depth-Buffer)
这是目前现代 GPU 和游戏引擎(如 Unity、Unreal)中使用最广泛的消隐算法。
原理: 在内存中开辟一块和屏幕像素一一对应的缓冲区,称为 Z-Buffer(深度缓冲)。里面存储的是当前每个像素点对应的最近物体的深度值。
具体步骤:
- 初始化时,将屏幕所有像素的深度值设为无穷远(最大深度)。
- 遍历场景中的每一个三角形,利用重心坐标插值计算它在屏幕上覆盖的每个像素的深度值。
- 如果新算出来的深度值比 Z-Buffer 中记录的深度值更近,就用新物体的颜色更新该像素,并更新 Z-Buffer 中的深度值;否则,直接丢弃。
优点:
- 极其简单,非常适合硬件加速
- 不需要对物体进行排序,支持任意顺序提交三角形
- 硬件层面的晶体管实现成本极低
缺点:
- 占用额外的显存(存储深度图,通常为 24-bit 或 32-bit 浮点)
- 如果两个面靠得极近,会因为浮点数精度不足产生锯齿状闪烁(称为 Z-fighting)。缓解方法包括增大近平面距离、使用反向深度缓冲(Reversed-Z)等
- 无法处理透明物体(透明物体需要额外排序,不能简单用深度判断)
空间物体级消隐算法
这类算法在三维世界坐标系中直接对物体进行几何运算和排序。实际渲染管线通常会在进入像素着色之前先用此类算法做预处理,大幅削减需要处理的面数。
背面剔除(Back-face Culling)
这是最简单、也是最高效的空间物体级消隐算法。对于任何一个构成封闭表面的多边形网格(Mesh),朝向背离相机的面永远被朝向相机的面遮挡。渲染这些”背面”是纯粹的浪费——背面剔除可以在几何处理阶段消除大约 50% 的多边形。
判别方法: 利用面的法向量与视线方向的点积。
设多边形面的外法向量为
- 若
:面朝向背离相机(背面),直接剔除 - 若
:面朝向相机(正面),保留并继续处理
在实际实现中,经过投影变换后,通常会利用多边形投影到屏幕后的顶点绕序(Winding Order)来判断。约定正面为逆时针(CCW),若投影后变为顺时针,说明当前看到的是背面,可以丢弃。
优点: 仅需一次点积运算或绕序判断,硬件实现极其简单,且在管线早期就能削减近一半的面数。
缺点: 仅对封闭曲面有效;渲染半透明物体时不能启用(需要同时看到正反面)。
画家算法(Painter’s Algorithm)
顾名思义,就像画家画油画一样:先画远处的背景,再画中景,最后画近处的物体——后画的自然就覆盖了先画的。
原理: 将场景中的所有多边形按照距离视点的远近进行从远到近的排序,然后严格按照排序结果依次绘制到屏幕上。
优点: 可以自然地处理半透明物体(如玻璃、烟雾),因为图层逐个叠加恰好符合透明混合的需求。
缺点: 无法处理互相循环遮挡或交叉相交的情况。
例如:
现代引擎中的消隐管线
在实际的现代图形引擎中,消隐机制通常是多种算法协同工作的分层体系,按照执行顺序从前到后依次为:
- 视锥体裁剪(Frustum Culling)——剔除完全不在视野内的物体
- 背面剔除(Back-face Culling)——干掉物体背向相机的面(~50% 的三角形)
- 遮挡剔除(Occlusion Culling)——提前剔除被前方大物体完全挡住的物体
- 深度缓冲(Z-Buffer)——在像素级别进行最终、最精准的逐像素消隐
前三个步骤在几何处理阶段削减了大量不需要渲染的面,让最终的 Z-Buffer 只需要处理真正可能可见的像素——这正是现代 GPU 能够以极高帧率渲染复杂场景的核心策略。
总结
- 三角形的五大特性(最少顶点数、严格共面、必定凸多边形、重心坐标插值、可三角化)使其成为图形学不可替代的基本图元。
- 消隐算法分为图像空间级和空间物体级两大类。Z-Buffer 是像素级的最终保障,背面剔除和画家算法在几何阶段提前削减面数,两者相辅相成共同构成了现代渲染管线中高效的可见性判定体系。
这次的插图来自画师 DityPretty
图片地址:https://www.pixiv.net/artworks/114607300