[简化版 GAMES 101] 计算机图形学 12:可见性与 Z‑Buffer 深度缓存

简化版 GAMES 101 计算机图形学 12:可见性与 Z‑Buffer 深度缓存

  • [Bilibili 同步视频](#Bilibili 同步视频)
  • [一、光栅化:把三角形 "铺" 在像素上](#一、光栅化:把三角形 “铺” 在像素上)
  • 二、可见性难题:物体互相遮挡,怎么画才对?
    • [1. 朴素思路:画家算法(Painter's Algorithm)](#1. 朴素思路:画家算法(Painter’s Algorithm))
  • [三、真正的工业级方案:深度缓存 Z‑Buffer 🚀](#三、真正的工业级方案:深度缓存 Z‑Buffer 🚀)
  • [四、Z‑Buffer 为什么强?3 个关键优势](#四、Z‑Buffer 为什么强?3 个关键优势)
    • [1. 时间复杂度极低](#1. 时间复杂度极低)
    • [2. 绘制顺序无关](#2. 绘制顺序无关)
    • [3. 完美解决循环遮挡](#3. 完美解决循环遮挡)
  • 五、细节与局限:这些坑要知道
    • [1. 深度图的颜色理解](#1. 深度图的颜色理解)
    • [2. 浮点精度问题](#2. 浮点精度问题)
    • [3. Z‑Buffer 处理不了透明物体](#3. Z‑Buffer 处理不了透明物体)
    • [4. MSAA 反走样 + 深度缓存](#4. MSAA 反走样 + 深度缓存)
  • [六、总结 ✨](#六、总结 ✨)

Bilibili 同步视频

简化版 GAMES 101 计算机图形学 12:可见性与 Z‑Buffer 深度缓存

在计算机图形学的世界里,把三维空间里的物体 "画" 到二维屏幕上,是一切渲染的起点✨。我们每天看到的游戏画面、3D 模型、特效动画,底层都离不开光栅化可见性判断这两大核心。今天就从最基础的三角形绘制开始,一步步讲清:屏幕为什么会锯齿、怎么正确处理遮挡、Z‑Buffer 到底如何工作。


一、光栅化:把三角形 "铺" 在像素上

屏幕本质就是密密麻麻的像素小方块 📱,每个像素颜色统一、位置固定。想把一个三角形显示出来,最直接的方式就是:

像素中心对三角形覆盖的区域做信号采样。

但这里会出现一个经典问题 ------走样(Aliasing)

直接采样会让边缘出现锯齿、闪烁,观感非常粗糙。

那怎么解决?

答案很优雅:先模糊,再采样

先对信号做低通滤波,把高频信息抹平,再去采样,混叠自然消失,画面立刻顺滑很多。

从频域角度看,这个顺序绝对不能颠倒

  • 先采样 → 频谱被搬移 → 产生不可逆转的混叠

  • 再模糊 → 只能截断信号,混叠依然存在

这就是为什么 "先采样后模糊" 永远行不通。


二、可见性难题:物体互相遮挡,怎么画才对?

单个三角形很好画,但真实场景里有成千上万个三角形,距离相机远近不同、互相穿插遮挡。

核心问题只有一个:

谁在前、谁在后?怎么让近处挡住远处?

1. 朴素思路:画家算法(Painter's Algorithm)

最直观的方案,来自油画大师的创作逻辑:

从远到近依次绘制

先画远山 → 再画草地 → 最后画树木,新内容覆盖旧内容,遮挡关系自然正确。

但它有两个致命短板:

  1. 排序昂贵

    n 个三角形需要 O (n log n) 复杂度排序,大规模场景扛不住。

  2. 深度环无法解决

    三个三角形两两互相遮挡:P 覆盖 Q、Q 覆盖 R、R 又覆盖 P。

    这种循环深度关系,根本排不出先后,画家算法直接失效。

现实渲染里,它只能用在极简单的场景。


三、真正的工业级方案:深度缓存 Z‑Buffer 🚀

为了搞定复杂遮挡,图形学引入了深度缓存(Depth Buffer / Z‑Buffer)

它的思想极其聪明:放弃对物体排序,只对像素负责

核心思想

每个像素,只记录一件事:

当前能看到的 "最近深度"(离相机最近的距离)。

渲染时同步维护两张图:

  • Frame Buffer:最终显示的彩色画面

  • Depth Buffer:只存每个像素的深度信息

深度约定:

  • 深度值 越小 → 离相机越近

  • 深度值 越大 → 离相机越远

Z‑Buffer 执行流程(超清晰)

  1. 初始化 Depth Buffer → 所有像素深度 = 无限远

  2. 遍历任意顺序的三角形,光栅化到对应像素

  3. 对每个覆盖像素:

    • 计算当前三角形在该像素的深度值

    • 如果 < 缓存里的深度:更新深度 + 绘制颜色

    • 如果 ≥ 缓存里的深度:直接丢弃,被遮挡

它完全不关心三角形先后顺序,只在像素级别做 "最小值更新"。

举个栗子一眼看懂

  • 先画红色三角形,某像素深度 = 5

  • 再画蓝色三角形,同一像素深度 = 3

  • 3 < 5 → 蓝色覆盖红色,深度更新为 3

如果深度 = 8:

8 > 5 → 直接忽略,不画也不更新。


四、Z‑Buffer 为什么强?3 个关键优势

1. 时间复杂度极低

假设每个三角形覆盖常数个像素,整体复杂度为 O(n)

不是排序,只是逐像素求最小值,效率碾压画家算法。

2. 绘制顺序无关

不管先画近还是先画远,只要深度判断正确,结果完全一致。

工程上极其友好,不用操心绘制顺序。

3. 完美解决循环遮挡

三角形互相穿插?无所谓。

Z‑Buffer 逐像素判断,谁近显示谁,彻底告别深度环死局。


五、细节与局限:这些坑要知道

1. 深度图的颜色理解

深度值越小(近)→ 颜色偏暗

深度值越大(远)→ 颜色偏亮

所以近处物体在深度图里通常偏黑,远处偏白。

2. 浮点精度问题

实际用浮点数存储深度,几乎不会出现两个深度完全相等

极端巧合下的深度冲突,工程上有专门处理方案。

3. Z‑Buffer 处理不了透明物体

透明物体需要混合颜色,不能简单 "近覆盖远"。

透明渲染必须用额外算法,Z‑Buffer 无能为力。

4. MSAA 反走样 + 深度缓存

想让边缘更顺滑?用 MSAA 多采样。

这时要对每个采样点单独存深度 ,而不是一个像素只存一个深度。

这也是很多作业与实战渲染的高分提升点。


六、总结 ✨

  • 光栅化:像素中心采样 → 先模糊后采样才是正确反走样。

  • 画家算法:简单直观,但无法处理复杂遮挡与深度环。

  • Z‑Buffer:逐像素记录最近深度,任意顺序、O (n) 效率、工业标准。

  • 局限:不支持透明,深度需注意浮点精度。

到这里,光栅化与可见性的核心逻辑就全部讲完了。

下一篇,我们进入更美的世界:光照与着色(Shading),看 3D 物体如何拥有真实质感。

相关推荐
游乐码20 小时前
Unity基础(十一 )资源同步加载
unity·游戏引擎
LONGZETECH20 小时前
汽车仿真教学软件技术实现深度解析:从三维建模到学情数据闭环
c语言·3d·unity·架构·汽车
游乐码1 天前
unity基础(九)协程原理
unity·游戏引擎
XX風1 天前
OpenGL OIT 之 Linked List 实现(上篇):原理、流程与缓冲区设计
图形渲染
winlife_1 天前
全程用 AI 做一款商业级手游 · EP0 立项:能做到吗、怎么做、边界在哪
人工智能·unity·ai编程·游戏开发·商业化·mcp·funplay
nnsix1 天前
Unity Texture2D的 Read/Write 选项
unity·游戏引擎
VcB之殇1 天前
[Three.js] 实现两个3D模型之间的粒子化切换
前端·javascript·three.js
winlife_2 天前
全程用 AI 做一款商业级手游 · EP1 地基:先搭框架层,不急着写玩法
unity·ai编程·游戏架构·mcp·框架设计·funplay
小贺儿开发2 天前
Unity VideoPlayer 播放控制器
unity·编辑器·播放器·视频·工具·videoplayer·互动