[简化版 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 物体如何拥有真实质感。

相关推荐
anxiao_m16 小时前
水利数字孪生怎么选?主流可视化渲染平台深度横向测评
大数据·前端·人工智能·图形渲染·云渲染
Cx330❀2 天前
Qt 多线程深度解析:从底层原理到 UI 线程与同步实战
开发语言·qt·ui·搜索引擎·性能优化·图形渲染
Martina_03213 天前
AI生成3D场景导入 Unity/Unreal 后,NPC 总串层?用6步检查导航高度与跨层连接
人工智能·游戏·数学建模·3d·unity·自然语言处理·aigc
扶尔魔ocy3 天前
【qt openGL入门笔记】FPS相机
qt·opengl
小贺儿开发3 天前
Unity 局域网遥控幻灯片展示工具 3.0
科技·http·unity·工具·ppt·通信·网页
扶尔魔ocy3 天前
qt openGL入门笔记】FPS相机和轨道相机
qt·opengl
狂野小白兔4 天前
AI游戏制作04——Codex 搭配 Godot MCP 全流程教程
人工智能·游戏·godot
沧沧凉凉4 天前
一段需求、零素材,Claude Code 派了 33 个代理给我做了个 3D 动作游戏
游戏·ai编程·three.js
扶尔魔ocy5 天前
【qt openGL入门笔记】基础光照
qt·opengl
扶尔魔ocy5 天前
【qt openGL入门笔记】坐标系统和摄像机
qt·opengl