news 2026/8/28 6:38:31

遮挡剔除 HZB

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
遮挡剔除 HZB

1. 引言

在实时渲染中,遮挡剔除(Occlusion Culling)是提升性能的关键手段之一。它的核心思想很简单:不绘制那些被其他物体挡住、最终不会出现在屏幕上的物体。而 HZB(Hierarchical Z-Buffer,层次 Z 缓冲)正是实现高效遮挡剔除的一种经典且强大的数据结构。本文将从零开始,用通俗的语言带你理解 HZB 的原理、构建方式以及它在实际渲染管线中的应用。

2. 为什么需要遮挡剔除

想象一个大型游戏场景:你站在一栋大楼前,身后是整座城市。如果 GPU 老老实实地把城市里每一栋楼、每一条街道的三角形都画一遍,那么大量被大楼挡住的物体其实根本不会出现在屏幕上,白白浪费了宝贵的渲染时间。

遮挡剔除要解决的就是这个问题:在绘制之前,先判断某个物体是否可见,如果不可见就直接跳过。常见的剔除手段包括:

  • 视锥剔除(Frustum Culling):剔除不在摄像机视野范围内的物体。
  • 背面剔除(Backface Culling):剔除背对摄像机的三角形。
  • 遮挡剔除(Occlusion Culling):剔除被其他物体完全遮挡的物体。

前两种相对简单,而遮挡剔除因为要判断“谁挡住了谁”,需要更巧妙的数据结构,HZB 就是其中的代表。

3. 从 Z-Buffer 到 HZB

要理解 HZB,先得回顾它的基础——Z-Buffer(深度缓冲)。

在渲染过程中,GPU 会为屏幕上的每个像素记录一个深度值,表示该像素距离摄像机有多远。当两个物体投射到同一个像素时,深度值小的(更靠近摄像机)会覆盖深度值大的。这个深度缓冲就是 Z-Buffer。

Z-Buffer 本身是逐像素的,分辨率很高。但如果我们想快速判断“一个很大的物体是否被遮挡”,逐像素检查显然太慢了。于是就有了 HZB 的思路:把 Z-Buffer 逐级缩小,每一级都记录上一级中更大(远)的深度值(即更远离摄像机的值),形成一棵“深度金字塔”

这样,当我们想判断一个物体是否被遮挡时,不需要看每一个像素,只需要在合适的层级上做少量采样即可。

4. HZB 的构建过程

HZB 通常不是直接证明“物体可见”,而是尝试证明“物体肯定被完全挡住”。只要无法确定,就保守地让物体继续绘制。

HZB 的构建本质上是一个降采样(Downsampling)的过程。假设原始 Z-Buffer 的分辨率是 1024×1024,那么构建过程如下:

  1. 第一级(Level 0)就是原始的 Z-Buffer。
  2. 第二级(Level 1)分辨率降为 512×512,每个像素取 Level 0 中对应 2×2 区域里的最大(远)深度值
  3. 第三级(Level 2)分辨率降为 256×256,每个像素取 Level 1 中对应 2×2 区域里的最大(远)深度值
  4. 以此类推,直到分辨率降到 1×1 为止。

为什么要取最大值而不是最小值?因为最大值代表“这个区域里离摄像机最远的深度”。如果一个物体的深度比这个最远值还大,说明它完全在这个区域之后,必然被遮挡。

在实际工程中,在普通 Z 和 Reversed-Z 中,深度数值的远近方向相反,所以实现里到底取min还是max不能死记。原则始终是一样的:不能漏掉任何可能可见的部分,降采样时取最远的深度值

5. 用 HZB 做遮挡剔除

有了 HZB 之后,遮挡剔除的流程大致如下:

  1. 把待检测物体的包围盒(Bounding Box)投影到屏幕上,得到一个屏幕空间矩形。
  2. 根据这个矩形的大小,在 HZB 中选择一个合适的层级。原则是:矩形越大,选择的层级越高(分辨率越低),这样只需要采样少数几个像素。
  3. 在选定的层级上,采样矩形覆盖范围内的深度值,取其中的最小(近)值
  4. 把物体的实际深度(通常是包围盒离摄像机最近的那个点的深度)与采样到的深度值比较:如果物体的深度更大,说明它完全被遮挡,可以剔除;否则保留。

这里的关键是“选择合适的层级”。如果层级选得太高(分辨率太低),采样结果过于粗糙,可能会误判(把本来可见的物体剔除掉);如果层级选得太低(分辨率太高),采样次数太多,性能收益不明显。工程上通常根据投影矩形的面积来动态选择层级。

6. 一个简单的伪代码示例

下面用伪代码描述 HZB 遮挡剔除的核心逻辑,帮助你理解整体流程:

// 判断物体是否被遮挡 bool IsOccluded(HZB hzb, BoundingBox bounds, Camera camera) { // 1. 把包围盒投影到屏幕空间 ScreenRect rect = ProjectToScreen(bounds, camera); // 2. 根据投影面积选择合适的 HZB 层级 int level = SelectLevel(rect.Area()); // 3. 在选定层级上采样深度,取最大(远)值 float maxDepth = hzb.SampleMaxDepth(rect, level); // 4. 计算物体离摄像机最近的深度 float objectDepth = bounds.NearPlaneDepth(camera); // 5. 如果物体深度更大,说明被完全遮挡 return objectDepth > maxDepth ; }

7. HZB 的优缺点

优点缺点
剔除效率高,适合大量静态和动态物体构建 HZB 本身需要额外的 GPU 开销
层级结构天然支持“由粗到细”的快速判断对细长或形状不规则的物体,包围盒投影可能不够精确
实现相对成熟,主流引擎均有支持需要维护深度缓冲,且更新时机需要精心设计

在实际项目中,HZB 通常不会单独使用,而是与视锥剔除、软件光栅化剔除等手段配合,形成一套完整的剔除方案。

8. 总结

HZB 是一种基于深度金字塔的遮挡剔除技术,核心思想是把逐像素的深度信息逐级降采样,从而用很小的代价快速判断物体是否被遮挡。它的构建过程简单、剔除效率高,是实时渲染中不可或缺的工具之一。

9.Tips

1、HZB 并不能完全判断所有遮挡情况,例如下图,下边一个简化的二维空间例子,A点比B点离摄像机更近,所以经过遮挡剔除算法并不能判断方块被遮挡,方块不会在遮挡剔除这个阶段被剔除。方块还是会被渲染,但是方块的像素颜色否显示在最终的画面上,还是看方块的每个像素的深度是否在相机的最近距离了

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/28 6:38:29

Matlab从入门到精通:核心思维、工具箱应用与工程实践全解析

1. 从零到一:我的Matlab入门心路与核心认知第一次打开Matlab,面对那个简洁的命令行窗口和复杂的工具栏,我和大多数新手一样感到茫然。它不像Python那样“亲民”,也不像C那样“硬核”,它自成一派,是工程计算…

作者头像 李华
网站建设 2026/8/28 6:38:09

古墓丽影亚特兰蒂斯遗迹远程玩 古墓丽影亚特兰蒂斯遗迹串流教程

怎么实现古墓丽影亚特兰蒂斯遗迹远程玩?不少游戏爱好者想要脱离电脑主机守在屏幕前的束缚,随时随地体验遗迹探险、对抗猛兽的乐趣,怎么才能实现古墓丽影亚特兰蒂斯遗迹远程玩呢?无界趣连2.0就是很合适的串流工具,用手机…

作者头像 李华
网站建设 2026/8/28 6:37:06

LLM空间推理能力差?从提示词到函数调用的工程纠正路径

在 Hacker News 上,“How do you correct spatial reasoning of LLMs?” 这个讨论所反映的问题,很多做 LLM 应用的团队都遇到过。文本摘要、意图识别、检索问答做得不错,一旦进入导航指令、室内布局、CAD 辅助、自动排版等场景,模…

作者头像 李华
网站建设 2026/8/28 6:33:03

蜂窝物联网LTE天线选型、仿真与排障实战指南

最近给一款智能水表挑天线,翻了几家厂商的产品页,发现一个挺有意思的变化:LTE天线这个大类下面,不知道什么时候多了一排新版本——FPC软板的、PCB贴片的、外置胶棒的、带IPEX端子的,频段覆盖从Band 3/8铺到Band 1/5/28…

作者头像 李华
网站建设 2026/8/28 6:30:30

必看!加拿大化妆品CNF注册流程,加拿大化妆品CNF认证检测要求

想将您的化妆品成功打入加拿大市场?了解并完成加拿大化妆品CNF注册是您必须跨越的第一道门槛。 加拿大化妆品CNF注册是指加拿大化妆品法规(Cosmetic Notification Form,简称CNF)的注册。加拿大化妆品CNF注册是由加拿大卫生部负责管…

作者头像 李华
网站建设 2026/8/28 6:30:27

【1980-2010】全国陆地植被碳密度|0.1°栅格数据

🔍 数据简介 本次分享1980-2010年陆地植被碳密度栅格数据集,全域统一测算、不区分植被类型,时序连续、空间完整,适配陆地碳循环、生态固碳、植被演变、区域生态评估等科研研究与专题制图。📦 数据详情 数据名称&#x…

作者头像 李华