中EN
概念页

剔除技术

Culling Techniques

剔除 (culling) 是在渲染前尽快去掉对最终图像没有贡献的部分。本页讲几何类剔除:背面剔除(含成簇背面剔除与法线锥)、视锥剔除(层次化、平面掩码)、室内场景的入口剔除,以及牺牲质量换速度的细节剔除和小三角形剔除。更复杂的遮挡剔除见 遮挡剔除。

基本概念(19.2 节)

  • 剔除理论上可发生在管线任何阶段,越早越好;"最快渲染的三角形是从未发送给 GPU 的那个"。剔除也可用于碰撞检测、物理、AI 等非渲染部分。
  • 理想的剔除只把精确可见集 (EVS)——所有部分或完全可见的图元——送入管线。能给出 EVS 的方面图 (aspect graph) 最坏复杂度可达 O(n9)O(n^9),不实用。实际算法计算潜在可见集 (PVS):若 PVS 完全包含 EVS(只丢弃不可见几何)则是保守的,总能得到正确图像,因此更常用;近似 PVS 可能漏掉可见物体导致错误图像。PVS 找到后仍由 z-buffer 解决逐像素可见性。
  • 粒度可以是三角形、整个物体或物体组。

背面剔除(19.3 节)

对实心不透明物体(且相机在物体外、没有近裁剪穿入),背向观察者的三角形看不见。三种等价判定:

  1. 屏幕空间:计算投影后三角形的有符号面积,按约定方向(如顺时针)为负即剔除,在屏幕映射后立即进行。
  2. 视空间:从三角形所在平面上一点(取一个顶点)指向视点的向量与三角形法线点积为负即背向(正交投影用负视线方向代替);等价于视点到三角形平面的有符号距离的符号,法线无需归一化。
  3. 裁剪空间:取 v=(vx,vy,vw)v=(v_x,v_y,v_w),计算行列式 d=∣v0,v1,v2∣d=|v_0,v_1,v_2|,d≤0d\le 0 则剔除。

Blinn 指出前两者几何上相同,只是计算空间不同;实践中屏幕空间测试更安全,因为视空间里略微背向的侧视三角形在取整到亚像素坐标后可能变成略微朝前。

注意事项:

  • 镜像变换(负缩放)会把背面变正面,反之亦然。像素着色器可用 gl_FrontFacing / SV_IsFrontFace 判断正反面;以前要显示双面物体只能渲染两遍。
  • 常见误解是背面剔除能减半三角形。室内的墙、地板、天花板大多朝向观察者,地形也大多可见,只有山背面受益。
  • 运动模糊时顶点线性运动的三角形可能在一帧内背向→朝前→背向,只按帧首尾判定会出错;可改写为 Bernstein 形式,用贝塞尔曲线凸包性质做保守测试。景深情况下,若整个镜头都在三角形平面的负半空间(背后),可安全剔除。

成簇背面剔除与法线锥

一次测试剔除一整组三角形。法线锥由法线 n\mathbf{n}、半角 α\alpha、锚点 c\mathbf{c} 定义(截断锥还需沿法线的两个偏移距离)。Shirman 与 Abi-Ezzi 证明:视点位于"正面锥"中则锥内所有面都朝前,位于"背面锥"中则全部背向。

对不截断的锥,若所有几何都位于 c\mathbf{c},视点 e\mathbf{e} 看到整锥背向的条件为:

n⋅(e−c)<cos⁡ ⁣(α+π2)=−sin⁡α  ⟺  n⋅(c−e)<sin⁡α\mathbf{n}\cdot(\mathbf{e}-\mathbf{c}) < \cos\!\left(\alpha+\frac{\pi}{2}\right) = -\sin\alpha \iff \mathbf{n}\cdot(\mathbf{c}-\mathbf{e}) < \sin\alpha

若几何位于以 c\mathbf{c} 为中心、半径 rr 的球内,则为

n⋅(e−c)<cos⁡ ⁣(α+β+π2)  ⟺  n⋅(c−e)<sin⁡(α+β),sin⁡β=r∥c−e∥\mathbf{n}\cdot(\mathbf{e}-\mathbf{c}) < \cos\!\left(\alpha+\beta+\frac{\pi}{2}\right) \iff \mathbf{n}\cdot(\mathbf{c}-\mathbf{e}) < \sin(\alpha+\beta),\quad \sin\beta=\frac{r}{\lVert\mathbf{c}-\mathbf{e}\rVert}

(式 19.2、19.3 在提取文本中排版错乱,按可完全确定的结构重建。)锥的计算:把所有三角形法线平移到同一点,求单位球面上包含它们的最小圆。量化后法线锥可存进 8×48\times 4 位。

静态网格立方体掩码(Haar 与 Aaltonen,《刺客信条:大革命》):给 nn 个三角形算一个最小立方体,每个面分成 r×rr\times r 个"像素",每个像素存 nn 位掩码表示从该像素对应锥台内看哪些三角形可见。相机在立方体外时直接查掩码即可保守剔除背面;在内部时全部视为可见。他们每面只用一个掩码、一次编码 64 个三角形,并用置位计数为未剔除三角形高效分配内存。

视锥剔除(19.4 节)

把物体的 BV 与视锥比较:完全在外则跳过,在内或相交则送入管线。配合 空间数据结构 可层次化:对 BVH 前序遍历,BV 在外则剪掉整棵子树;完全在内则其子树不再需要任何视锥测试;相交则继续测试子节点,叶节点相交时其几何被送入管线(但不保证都在视锥内)。

优化手段:

  • 多级 BV:球与视锥相交时,若已知 OBB 小得多,可再做更精确的 OBB 测试。
  • 平面掩码 (plane masking):记录 BV 完全位于哪些视锥平面内侧(位掩码),子节点只需测仍相交的平面;根测 6 个平面,越往下越少。
  • 时间相干:把上一帧拒绝该 BV 的平面存起来,下一帧先测它。
  • CPU 上做逐物体剔除、GPU 上还有更细粒度剔除时,CPU 只需测左右上下四个平面;还可用 apex point map 得到更紧的包围体。
  • 远处常用雾掩盖物体在远平面突然消失。

有些游戏引擎不用层次 BVH,而是每个物体一个 BV 组成线性列表,因为更容易用 SIMD 和多线程实现;但 CAD 这类大部分几何都在视锥内的应用应避免,层次剔除可在节点完全在内时立即绘制。

入口剔除(19.5 节)

针对建筑模型:墙是室内的大遮挡物,所以入口剔除是一种遮挡剔除,也是视锥剔除的扩展。场景预处理为单元 (cell)(房间、走廊)和连接它们的入口 (portal)(门、窗),存成邻接图。自动化划分对现代复杂场景极难,目前多为手工定义。

Luebke 与 Georges 的方法:

flowchart TD
  A["渲染视点所在单元"] --> B["遍历该单元的入口"]
  B --> C{"入口在当前视锥内?"}
  C -- "否" --> D["忽略该入口及其后单元"]
  C -- "是" --> E["把视锥缩小到紧贴入口"]
  E --> F["用缩小后的视锥剔除并渲染相邻单元"]
  F --> B

如上图递归进行,例如透过门看到房间的三扇窗,只有门与某扇窗都能看到的部分才渲染。要点:

  • 用帧号给已渲染物体打标记,避免透过两个窗口被渲染两次(低效,透明物体还会出错),也免去每帧清空标记。
  • 实际入口用 AABB 高估,可用模板缓冲遮掉真实入口外的部分,或设置剪裁矩形;这样透明物体即使渲染两次也只影响各入口的可见像素一次,可省去打标记。
  • 把视锥在镜面处反射,可用于平面反射的内容裁剪;其他变换可做简单折射。

细节剔除与小三角形剔除(19.6 节)

  • 细节剔除(屏幕尺寸剔除):把 BV 投影到屏幕估算像素面积,低于阈值就不处理。依据是视点运动时小细节几乎没有贡献,视点静止时通常关闭。可在场景图上层次化进行,游戏引擎常用。
  • 小三角形剔除:每像素中心一个采样时,小三角形很可能落在采样点之间,而且光栅化效率低。在 GPU 剔除代码中可计算三角形二维 AABB,若
any(round(min) == round(max))\texttt{any(round(min) == round(max))}

为真则剔除(像素中心在 (x+0.5,y+0.5)(x+0.5, y+0.5),x 或 y 方向取整到同一坐标即说明不覆盖任何采样点)。这是保守的:有些不覆盖采样的三角形也剔除不掉。

取舍

技术优点局限
背面剔除几乎免费,硬件开关室内、地形收益小;镜像变换需翻转
成簇背面剔除一次剔除一组需预计算法线锥或掩码
视锥剔除大场景收益巨大大部分可见时只增加开销
入口剔除室内极有效单元与入口多为手工
细节/小三角形剔除便宜细节剔除牺牲质量

GEA 的视角:应用层的剔除(卷 II 11.5.1)

GEA 把剔除放在应用层的第一项职责里:"最便宜的三角形是你永远不画的那个";构建可见网格实例列表的过程叫可见性判定(卷 II 11.5.1,应用层见 图形栈与渲染引擎架构)。

背面剔除

  • 用环绕顺序判断朝向:沿约定的环绕顺序走过顶点时,法线 n\mathbf{n} 按右手方向指向三角形"正面"。取三角形法线与观察向量 v\mathbf{v} 的点积,n⋅v≥0\mathbf{n}\cdot\mathbf{v}\ge 0 即视为背向(卷 II 11.5.1.1)。这里 v\mathbf{v} 是相机的观察方向;本页 RTR4 的视空间判定用的是从三角形指向视点的向量,方向相反,所以符号也相反,两者等价。
  • 双面三角形就是不做背面剔除的三角形,D3D11 中把剔除模式设为 D3D11_CULL_NONE。
  • 原书问题(D3D11 剔除模式说反了):GEA 写道 D3D11 默认把顺时针当正面(这一点正确,D3D11_RASTERIZER_DESC::FrontCounterClockwise 默认 FALSE),但又说设为 D3D11_CULL_FRONT 时"背向三角形不会被画"、设为 D3D11_CULL_BACK 时"正向三角形不会被画",正好说反。微软文档(MS Learn「D3D11_CULL_MODE enumeration」)明确:D3D11_CULL_FRONT = 不画正向三角形,D3D11_CULL_BACK = 不画背向三角形(默认光栅化状态就是 D3D11_CULL_BACK)。要做常规背面剔除应设 D3D11_CULL_BACK。
  • 环绕顺序和法线方向要在全部几何中保持一致(例如封闭物体法线一律朝外),背面剔除才能工作(卷 II 11.3.6.1)。

视锥剔除:球体测试

  • 用物体包围体与视锥六个平面做简单测试,完全在外的从渲染列表中剔除。包围体通常用球,因为特别好剔除(也用 AABB 等)。
  • 思路:把每个平面向外推出球半径的距离,看球心在每个平面的哪一侧。实际不用移动平面:把球心代入平面方程 h=ax+by+cz+d=n⋅P−n⋅P0h=ax+by+cz+d=\mathbf{n}\cdot\mathbf{P}-\mathbf{n}\cdot\mathbf{P}_0 得到到平面的有符号距离 hih_i,与半径比较即可(若平面法线朝视锥内侧,任一平面上 hi<−rh_i<-r 即球完全在外可剔除,六个平面都满足 hi≥−rh_i\ge -r 才保留;这一判断是保守的,靠近视锥角落的球可能被误留)(卷 II 11.5.1.2,平面方程见 几何图元的表示)。场景图可以先排除离视锥很远的物体,见 空间数据结构。

入口与反入口

  • 入口 (portal):把世界分成由门窗等开口连接的半封闭区域,开口用多边形表示。先渲染相机所在区域,再对区域里的每个入口,从焦点穿过入口多边形各边伸出平面,构成类似视锥的体积,邻区内容按它剔除(卷 II 11.5.1.4)。这与本页「入口剔除」一致。
  • 遮挡体/反入口 (antiportal):反过来,从焦点穿过遮挡物的轮廓边伸出平面,得到被遮挡的锥形区域,完全落在其中的远处物体被剔除(卷 II 11.5.1.5)。
  • 取舍:入口适合门窗不多的室内,入口只占视锥体积的一小部分,入口外的大量物体被剔掉;反入口适合室外大场景,近处物体常挡住大片视锥。PVS 见 遮挡剔除 中的 GEA 部分。
  1. realtime_rendering_4ed.pdf 第 19 章 Acceleration Algorithms
  2. Game_Engine_Architecture_4th_Edtion_Volume_2_-_Jason_Gregory.pdf
  3. Jason Gregory《Game Engine Architecture》第 4 版(2026)卷 II 第 11 章 11.3.6.1、11.5.1 节

相关页面

图形学空间数据结构Spatial Data Structures空间数据结构把几何体按 n 维空间组织起来,通常是层次化的树,使"几何体是否重叠"一类查询从 O(n) 降到大约 O(\log n)。常见类型有包围体层次 (BVH)、BSP 树(轴对齐的 k-d 树与多边形对齐两种)、四叉树/八叉树(含松散八叉树),以及更偏向组织模型关系的场景图。它们是剔除、光线求交、碰撞检测等加速算法的基础。图形学遮挡剔除Occlusion Culling遮挡剔除尽早剔除被其他物体挡住的物体,避免它们在 z-buffer 中被光栅化、深度比较甚至着色。本页覆盖遮挡剔除的分类与通用框架、GPU 遮挡查询、层次 Z 缓冲 (HZB) 及其在现代引擎中的简化变体(含两遍法、软件光栅化遮挡),以及在 CPU/GPU 上按物体—簇—三角形多粒度组合剔除并用间接绘制提交的剔除系统。图形学细节层次Level of Detail细节层次 (LOD) 在物体对图像贡献变小时改用更简单的表示。LOD 系统由三部分组成:生成(简化或手工制作多个版本)、选择(按距离、投影面积等收益函数挑选)、切换(尽量减少跳变 popping)。LOD 主要减少顶点处理,也通过减少 quad 过度着色降低像素开销;进一步还可在预算约束下全局选择 LOD,实现时间关键(恒定帧率)渲染。图形学网格整合与顶点法线Mesh Consolidation & Vertex Normals整合 (consolidation) 指把零散多边形合并成共享顶点的网格、让所有面朝向一致、判断是否为实体,并生成平滑的顶点法线与折痕边。这些步骤是背面剔除、折痕检测、阴影体、碰撞检测、3D 打印等的前提。图形学局部反射探针Localized Reflection Probes镜面全局光照需要高角分辨率但只关心反射方向附近的小立体角。实时中最流行的方案是在场景中稀疏放置局部环境贴图(反射探针),配合反射代理体做视差校正;它实现简单、快、美术可控,但有拉伸和漏光问题。另有体素锥追踪和平面反射等替代方案(RTR4 11.6–11.6.4 节)。图形学合并阶段与帧缓冲Merging & Framebuffer合并阶段把像素着色算出的片元颜色和缓冲区里已有的颜色结合起来,同时负责深度测试、模板测试和混合。它通常不可编程但高度可配置,也叫 ROP(光栅操作或渲染输出单元)。帧缓冲是系统中所有缓冲区的总称。图形学雾与简易体积光照Fog & Simple Volumetric Lighting这类"老派"技巧依赖经验模型,但至今仍然好用:深度雾、高度雾和局部雾体积用透射率混合雾色;光柱可用拉伸的面向相机粒子、单次散射的解析积分、平面切片,或屏幕空间径向模糊实现(RTR4 14.2 节)。图形学运动模糊Motion Blur运动模糊可看作时间域的抗锯齿:快门打开期间物体或相机的相对运动在画面上拖出模糊,没有它快速运动的物体会在帧间"跳跃"。实时做法以速度缓冲为核心,用"边收集边散布"思路:按瓦片求最大速度、扩展到邻域,再沿速度方向对每个像素采样并处理遮挡。游戏中还需考虑玩家控制下的视角,常只对物体或平移做模糊(RTR4 12.5 节)。图形学分块着色Tiled Shading分块着色把屏幕划分为瓦片(如 32×32 像素),先为每个瓦片建立可能影响它的光源列表,着色时每个像素在一次着色器调用中只遍历所在瓦片的列表。它可用于延迟着色(tiled deferred),也可用于前向着色(tiled forward,又称 Forward+)。配合 z-prepass 得到的瓦片深度范围可进一步剔除光源,但深度不连续会削弱效果,于是出现 HalfZ、2.5D 剔除等改进。图形学分簇着色Clustered Shading分簇着色把整个视锥(而不只是屏幕平面)划分为三维单元——簇 (cluster),按簇建立光源列表。与依赖场景几何深度的分块着色不同,簇的划分与几何无关,可只由视图和光源计算,因此对相机位置的性能波动更小、对深度不连续更稳健,并为不透明、透明、体积物体提供统一的光照方案。它同样可配合前向或延迟着色,并衍生出 z-binning、光源树等更省内存的变体。本页还汇总了各类多光源方案的对比。图形学VR 立体渲染优化VR Stereo Rendering OptimizationVR 每帧要为两只眼渲染,并经合成器做镜头畸变与色差校正。本页讲厂商 SDK/API 的帧流程与内建优化(分层合成、隐藏区域网格、裁剪过的畸变网格),立体渲染如何避免工作量翻倍(合并视锥剔除、实例化、多视图扩展、多 GPU 广播、远景单目渲染),以及利用光学和人眼特性减少外围像素着色的技术:多分辨率着色、镜头匹配着色、径向密度遮罩、固定注视点渲染与注视点渲染。游戏数学相交测试基础与分离轴Intersection Test Fundamentals & Separating Axis相交测试判断两个对象是否相交(包含、边界相交或分离),有时还需要最近交点或穿透深度与方向,是碰撞检测、视锥剔除、拾取和光线追踪的基础。本页汇总 RTR4 第 22 章的通用工具:光线与曲面的表示、常见包围体定义(AABB、OBB、k-DOP、凸多面体、胶囊与菱形体)、分离轴测试 (SAT)、几何概率与表面积启发式 (SAH)、设计相交例程的经验法则,以及基于 GPU 的拾取。游戏数学视锥相交测试View Frustum Intersection Tests层次视锥剔除遍历 BVH 时最频繁调用的就是视锥与包围体的测试,理想结果分三态:完全在外(剪掉子树)、完全在内(子树免测)、相交(递归)。本页讲从组合矩阵直接提取六个视锥平面、把"BV 对视锥"转化为"点对扩张/收缩体积"的推导思路,以及视锥-球、视锥-盒的高效保守测试及其误报情况。游戏开发 · UE5世界分区World Partition世界分区 (World Partition) 是 UE5 的自动数据管理与基于距离的关卡流送 (Level Streaming) 系统:整个世界存为一个持久关卡,按可配置的运行时网格划分为单元格 (Cell),由流送源 (Streaming Source,默认是玩家控制器) 按距离加载/卸载。它配合一 Actor 一文件 (One File Per Actor, OFPA) 支持多人协作编辑,用数据层 (Data Layers) 按玩法状态切换内容,用分层细节层次 (Hierarchical Level of Detail, HLOD) 在远处以代理网格显示未加载的单元格。游戏开发 · UE5Nanite 虚拟化几何体Nanite Virtualized GeometryNanite 是 UE5 的虚拟化几何体 (Virtualized Geometry) 系统:导入时把网格切成分层的三角形簇 (Cluster),渲染时按相机视角逐簇选择细节层次并无缝拼接,按需从磁盘流送,并在绕过传统绘制调用 (Draw Call) 的独立通道中渲染,使帧预算不再受多边形数、绘制调用和网格内存约束。游戏开发 · UE5虚拟阴影贴图Virtual Shadow Maps虚拟阴影贴图 (Virtual Shadow Maps, VSM) 是 UE5 默认的阴影方法:概念上就是分辨率极高(虚拟 16k×16k)的阴影贴图,切成 128×128 的页 (Page),只为屏幕上需要着色的像素分配和渲染页,并跨帧缓存;方向光用 clipmap 覆盖大范围,软阴影由阴影贴图光线追踪 (Shadow Map Ray Tracing, SMRT) 生成。它为 Nanite 设计,与 Nanite 一起使用时最高效。综合帧时间预算与渲染性能Frame Budget & Rendering Performance本页把 wiki 中分散在 RTR4 第 18~23 章的性能知识串成一条线:一帧的时间预算由最慢的管线阶段决定,先用毫秒帧时间度量并定位瓶颈,再按瓶颈所在位置——CPU/驱动、几何、像素、带宽/内存——选用对应手段;最后从 GPU 硬件机制(占用率、HiZ/early-z、压缩、分块架构)理解这些手段为何有效。各结论的细节与出处见所链接的概念页。图形学大场景渲染与虚拟纹理Large Scenes & Virtual Texturing当场景数据远大于内存(如主机只有 8 GB,而游戏世界有数百 GB)时,需要按需把数据流送进内存。本页讲三类技术:虚拟纹理(把巨大的 mipmap 链切成瓦片,只让可见瓦片驻留在显存,通过页表/间接纹理寻址)、纹理转码(磁盘上用高压缩比的可变码率格式,加载时转成 GPU 块压缩格式),以及按平面瓦片组织资产的通用流送。这些方法几乎总是与剔除和 LOD 配合使用;地形部分见 地形渲染。游戏数学几何图元的表示Geometric Primitive Representations除点、向量、矩阵、四元数外,游戏引擎还天天用到直线/射线/线段、球、平面、AABB、OBB、视锥和凸多面体区域。本页按 GEA 整理它们在内存中如何表示以及最基本的「点在内部吗」测试;各种求交与重叠算法见 RTR4 来源的相交测试系列页面。图形学图形栈与渲染引擎架构Graphics Stack & Rendering Engine Architecture渲染引擎要解决的"渲染问题"是:给定由场景元素、虚拟光源和虚拟相机组成的虚拟世界,生成相机看到的二维彩色图像。GEA 把它拆成可见性问题和光照问题,按解法把引擎分为光线追踪、深度缓冲光栅化、辐射度和混合四类;光栅化引擎通常采用立即模式的两层结构:下层是图形管线,上层是负责剔除、提交几何和设置着色器参数的应用层。本页讲这套整体架构,管线内部见 渲染管线。游戏开发 · UE5UE5 渲染架构UE5 Rendering ArchitectureUE5 的渲染器是独立的 Renderer 模块,在渲染线程 (Rendering Thread) 上以「场景代理」镜像游戏线程的组件状态,每帧按固定顺序执行深度预通道、G-buffer 基础通道、光照、雾、半透明和后处理。现代渲染代码用渲染依赖图 (Render Dependency Graph, RDG) 声明通道与资源,由 RDG 自动排屏障、复用瞬态内存、并行录制;最终命令经 RHI 线程翻译成 D3D12/Vulkan 等图形 API 调用。默认走延迟着色 (Deferred Shading),也可切换前向着色 (Forward Shading)。游戏数学光线求交测试Ray Intersection Tests光线求交用于拾取、光线追踪、地面高度查询等。本页给出四类经典测试:光线-球(代数解与带早期拒绝的几何优化解)、光线-盒(平板法与光线斜率法)、光线-三角形(Möller-Trumbore,直接从顶点求重心坐标与距离)、光线-多边形(先求平面交点,再投影到二维做交叉数测试)。共同思路是先做便宜的拒绝测试、推迟除法与开方、必要时降维。

输入关键词开始搜索

滚轮或双指缩放 · 拖动平移 · 双击放大 / 还原