Umbra 3:次世代的遮挡裁剪
原文链接:http://www.gamasutra.com/view/feature/164660/sponsored_feature_next_generation_.php?print=1
来自 Umbra Software
[在这个主办方特辑中,Umbra Software讨论了当前使用的大量裁剪遮挡方法的优缺点,并解释了它自己的自动化遮挡裁剪系统,能够接受任何类型的多边形数据组作为输入。
Umbra Software成立于2006年,是一家芬兰的中间件公司,专注于图形渲染技术。当公司研发出dPVS系统并继续将它开发到Umbra遮挡裁剪中间件的雏形时,从Hybrid Graphics独立出来。Umbra的核心技术团队从2000年开始就从事遮挡裁剪领域的工作。他们的技术被广大开放商用于游戏中,诸如Bungie, BioWare, 38 Studios, Square Enix Co., IO Interactive, Remedy, Specular Interactive以及许多其他帮助这个技术成型的公司。]
请先观看一段Umbra 3的视频。可以通过这里联系Umbra公司。
简介
在游戏中渲染3D世界的视野时,花费在处理对玩家不可见元素上的资源是难免浪费的。这些资源可以被更好地用来增加可见元素的视觉复杂度或者提高帧率。因为这个原因,我们必须识别对玩家不可见的对象。
在一个特定视角,因为被其他元素挡在后面,由此决定了不可见元素的集合,这就是遮挡裁剪。
图1:遮挡裁剪基础。视锥体中的红圈对摄像机是不可见的,因为它被蓝色矩形遮挡住了。上面的红圈在这里也是不可见的,因为它和视锥体没有交集。
在实时交互的应用程序中,遮挡裁剪一般被用作渲染优化的技术。它允许产出的帧率是让人感觉在连续播放。然而,大量的可见性信息是在渲染之外使用的。知道一个对象当前是否可见可以被用于:
- 影响AI行为。
- 简化或禁止物理模拟和动画。
- 降低通过网络复制其他玩家坐标的量。
访问遮挡裁剪系统的数据时,一些可取的属性有:
它工作起来是自动的通用的
理想化中,遮挡裁剪系统是对任何类型的3D内容都起效的,从简单的对象查看器到大型的虚拟世界,并且不需要美术在构建游戏世界时手动做什么额外工作。而且,系统应该对美术的创造性没有任何限制。最后,系统应该不依赖任何特定的硬件特性、渲染约定或者授权方法及工具。
它是保守性地正确的
系统有时候决定完全或者部分可见的对象完全被遮挡了,最终产生的是渲染瑕疵,但是系统有时候将完全被遮挡的对象确定为可见,一般产生的是正确的图像输出。
它会附加作用
为了渲染目的,遮挡裁剪必须排斥和在视锥体内渲染所有对象相关的解决方案。举例来说,一个体育游戏是基于一个场馆的,任何时候只有一小部分的游戏内容被遮挡,对遮挡系统来说这就不是一个适用者。花费在决定遮挡上的努力全部白费了,因为没有获取任何收益。然而,需要画面复杂度以及3D世界的大量细节时,遮挡系统的价值就显著提升了。
在这篇文章中,我们先简单介绍问题的领域,并且看一下当前使用的遮挡裁剪的常用方法,特别关注它们在游戏开发环境中面临的挑战。随后,我们会描述一个新颖的遮挡裁剪方法,是为了满足我们合作伙伴和客户开发次世代游戏的需求所开发的。
这个方法被称为Umbra 3遮挡裁剪系统。
背景介绍
3D图形中的遮挡裁剪的祖先是在隐藏的线和面的确定算法。这些算法对在3D空间中2D投影下产生正确画面是必要的。
问题很容易领悟——从光线出发到游戏世界中的眼睛,在面之间遍历,只有没碰到障碍的会对最后的画面有贡献。这是可见性问题的一个例子,并且已经准备好建议一个可行的3D渲染解决方案:我们可以简化从光线跟踪,从眼睛出发,并且找到第一个每条射线都相交的面。
所有的现代的多边形光栅渲染器,无论软件还是硬件的,每次采样间记录最小的距离,并且只在距离值比当前最小值还小的时候才更新采样。这个解决方案就是我们知道的Z-buffering或者深度缓冲,为Z值维护的额外缓冲。2D投影和光栅采样已经做了大量工作,计算Z值相对来说很廉价,并且能保证正确的视觉结果。将图元前后排序后计算量会降低:优先渲染最近的图元意味着其他与图元沿着同样的射线过来的贡献会被深度测试拒绝,因此,任何被最终确定为隐藏采样的计算,诸如顶点属性插值或者查询纹理,都可以被跳过。
图元渲染排序后的Z-buffering已经非常接近理想状态,仅需要为每个输出像素计算单一的值。
不幸的是,裁剪在3D游戏应用程序的渲染管线中很后面才出现。在渲染器拒绝一个被遮挡的采样时,采样从提供输入几何体和独立资源到GPU来做逐顶点处理,三角形建立和光栅化开始,已经经过了图形管线的好几个阶段了。渲染管线中存在early Z-culling的方法,但最终最多计算节省是通过在传入渲染子系统前裁剪引擎中最大的可渲染实体。
一般来说,遮挡裁剪都和这类渲染优化有关。
遮挡体光栅化
大多数的运行时遮挡裁剪策略通过相当于针对潜在被遮挡的单个对象或对象层次结构的变换后的包围盒,做逐个采样的深度测试,来获悉一个对象是否可见。挑战就是在实际渲染执行前,建立视口的深度缓冲预估。
一个广泛使用的解决方案是使用一个单独渲染深度的pass或者GPU上前一帧的深度结果,并且使用遮挡查询。一次遮挡查询返回采样潜在通过深度测试的数目,而不用实际处理或者写像素值。这个方法的挑战是在CPU和GPU之间同步,需要传输测试数据并且获得遮挡信息。实际中,除了渲染优化外基本上不可能使用这个方法。
从上所述来看,没有额外工作用来生成深度缓冲,它就代表了任何遮挡者几何体最终确定的画面。为了允许CPU和GPU异步执行,并且最小化它们之间的交互,这些系统通常使用前一帧的深度缓冲结果,因此无法保证严密的裁剪。
另一个选择是将遮挡者几何体的简化表示光栅化到一个在CPU中的较小分辨率的深度缓冲。为了获得严密的裁剪,几何体必须没有超越光栅器实际结果的覆盖范围。通常美术手动创建这些遮挡模型,从实际模型中逐条边复制过来。
潜在可视集(PVS)
当early depth buffer生成和遮挡测试的运行时开销变得不可行并且遮挡几何体基本是静态的,一个切实可行的替代方案是,在预处理阶段,在view cell和可渲染实体之间确定并存储可见性关系。实体集合从一个view cell确定可见性,就是所谓的潜在可视集。运行时操作包括简化查找当前摄像机位置的view cell,并且从内存中查找可视集。在简单的案例中,关卡设计者可以手动构建可见性关系,但是通常的方法是从一个view cell采样可见性,或者通过全方向的射线检测或光栅化。通过增加每个view cell的采样数量,错误的总量在损失计算所需要的时间的情况下可以被控制。除了静态的目标对象之外,体积化的可见性信息用target cell的形式可以被储存在可视集中,能够同样裁剪非静态实体。
潜在可视集的生成是可以自动的,但是要获得合理的裁剪结果必须生成大量的数据。预处理阶段的采样时间会减慢资源的迭代周期,大量的代表可见性关系的数据会迅速变得无法管理。实际上,因为可见性关系是全局整体的,在遮挡几何体上的一个微小改变会导致很远处的可见性关系都要改变,并且在原先改变的每边都需要重新计算很大区域的潜在可视集。
Portals and cells
第三类遮挡裁剪系统基于将游戏世界分割成cell,并且通过2D portal来捕捉邻接cell之间的可见性。运行时的操作是找到摄像机所在的cell,遍历结构化的cell图,通过对遍历过的portal视锥体裁剪的方法来限制可见性。在预处理阶段,对象被分配到cell中,他们的可见性通过访问他们所在的cell所决定。当游戏世界中有明显的热点可以让关卡设计者放置portal时,这个方法很有效,比如在室内设定中,屋子通过门或者窗连接。
Portal和cell的数据是游戏世界的简化遮挡模型,存储了非遮挡体以及它们之间的连接性,而不是遮挡体。相对轻量的运行时开销可以获取准确且保守的遮挡结果时,手动放置cell和portal是需要非常密集的人力的,容易出错而且会显著提高资源修改的代价。
Umbra 3: 次世代的遮挡裁剪
Umbra 3遮挡裁剪系统就是设计用来克服以上章节描述的挑战的。
Umbra 3基于这样一个想法,将3D世界从美术创建的细致多边形转换到简化表示。转换主要致力于捕捉重要的遮挡属性,同时忽略和遮挡裁剪处理基本无关的细节信息。这个方法类似于手动构建portal和cell结构图。而Umbra 3使用的遮挡模型是自动生成的protal和cell图。
一般来说,portal裁剪可以完美运行的游戏世界已经被设计成可以允许少量的portal来捕捉粗略的遮挡信息:空旷的空间通过狭窄的通道连接,大多数连接性都是在地面上或者接近地面。一个通用的解决方案不能对游戏世界有这样的假设,而且必须对所有3个维度中任意复杂的拓扑结构有效。更大数量的cell和portal需要捕捉大型室外区域的遮挡,这些区域都有独立的遮挡特性。
Umbra 3由2个组件组成:
- 优化器(Optimizer)
优化器是在预处理阶段整合到游戏编辑器中的。它接受任何类型的多边形数据组作为输入,并将整个场景离散到三维像素来生成view cell。随后view cell会通过portal连接。Portal和cell结构图数据存储到优化的数据结构中,然后在运行时被访问。 - 运行时组件
运行时组件光栅化一个软件深度缓冲,这个缓冲用来测试可见性。它允许每帧大量动态对象的测试,几乎没有计算开销。算法的精确度接近硬件的遮挡查询,但是作为一个纯粹的软件实现,相对于基于硬件的遮挡裁剪,不受任何同步和可移植性问题限制。
概念上的Umbra 3架构如下图描述:
自动生成portal和cell图在工程上的挑战总结如下:
- 随机的多边形组必须可以至少勉强转换到典型的protal和cell图,这样能够允许控制图的大小比上遮挡粒度。
- 有效的运行时裁剪算法是需要的。它必须使用portal和cell图,而且可以应付相当大数量的portal。此外,它必须服从保守的裁剪结构在使用有限的内存空间情况下,运行足够快不能在最小的遮挡情况下成为性能瓶颈。
后面两章将会描述Umbra 3遮挡裁剪系统中实现的针对这两个挑战的解决方案。
遮挡数据生成
在高的层面上,3D场景图是通过原始的甚至分散的初始化portal图生成的。通过去除对整个遮挡基本没有贡献的数据,结构图被逐步简化。输入的遮挡体模型仅被用在初始的cell生成阶段来决定一个独立的三维像素是否可见,或者一个轴对齐的盒子,是实心的还是空心的。
三维像素化允许算法可以独立于几何体的复杂度;事实是,只需要保守的近似真实几何体的结果让它变得可能。
初始cell生成
初始结构图通过第一次将场景几何体细分到轴对齐的格子来定义。初始格子节点的大小要被选为和我们希望采样场景遮挡特性的粒度匹配。接着,我们进一步将几何体细分到三维像素,基于三维像素和几何体的交集来标记几何体是实心的还是空心的。
三维像素被用来查找立方体中非连接区域,通过大量填充空的三维像素,就是递归地组合邻接的空心三维像素在一起。空的三维像素集合是我们结构图的初始候选者cell。对每个这样的空心三维像素组,我们查找立方体面之间的交集,并且储存交集的轴对齐包围盒作为portal矩形。为了将初始cell连接到结构图,portal和立方体另外一个面生成的邻接的portal匹配。
图2:初始cell生成。左起第一张图表示一个格子节点的2D横截面,有个具体的几何体在里面。在第二张图中,几何体近似实心的三维像素。在第三张图中,空的三维像素被填充到三个不同的区域中,形成了初始view cell。Portal在空心三维像素和立方体面的相交处生成。
使用几何体离散的体积化表示的好处是很明显的。任意的多边形数据和轴对齐包围盒相交会在数值健全性的方式上完成,一旦三维像素形成了,算法独立于输入数据的复杂度,而且只需要处理简单的整数格子。因为我们采用保守的遮挡表示,我们不必完全跟着几何体来,只要跟着保守的一边。
这个方法唯一的例外是格子节点内的连接性决定。如果模型数据中有个洞,比选定的三维像素尺寸小,它就不会被一系列的空三维像素捕获,而且对连接性不会有贡献。幸运的是,小的孤立的可以看穿的洞相对来说不是很普通,通常也不是游戏中想要的。
在这个时候,如果有静态目标对象的信息,我们可以进行到近似三维像素化他们的几何体,并且通过查找邻接空的三维像素属于的cell,将对象分配到初始cell。自然地,如果同样的几何体既被用作遮挡者又被用作静态目标对象,我们可以节省一半的工作。
图3:实心的遮挡者三维像素,显示为线框模式的立方体。注意有些对象不考虑遮挡。
结构图简化
如果在portal和cell结构图中,我们可以找到遮挡值最小的portal,我们可以通过组合portal连接在一起的cell来移除portal。这个方法形成了一个简化的结构图,最小化了全局遮挡信息的损失。迭代地进行到portal裁剪的阈值,或者一个固定的内存预算值,我们可以控制最终结构图的成本收益比。
优化的结构图通过组合portal是最差的全局遮挡值的两个cell在一起来简化,需要有反作用的昂贵的全局结构图分析,因为可见性基本上是全局属性。然而,本地的启发式方法可以应用,来快速去除结构图中最无用的portal。简化可以在层次化的方式下完成,当我们从层次结构前进到更大的范围时,降低portal遮挡的阈值。在层次结构中每一个新的层,我们将邻接体积的外部portal连接,并且对新组成的结构图运行简化。
层次化的简化同样提供输出遮挡数据的LOD描述的机会。运行时算法可以使用这些输出,根据离视点的距离,来选择遮挡所使用的级别。
图4:一个游戏世界中生成的cell的俯瞰图,既包含了室内区域(左边)和室外区域(右边)
视野树
Portal和cell结构图可以变得极其复杂。通过分割到连接的三维像素组以及子cell组合而形成的最终游戏的cell,已不容易被简单的结合体形状捕捉,而且就算对一个小场景存储复杂的三维像素结构也是不切实际的。为了在运行时使用portal和cell数据,另一个数据结构是需要的,用来在结构图中精确定位和摄像机位置相关的cell。这个数据结构就被称为视野树。
概括来说,视野树按照下列步骤建立:
- 属于同一个cell的两个相邻空三维像素可以被一起压缩,因为分开存储它们不会增加任何信息。大的空区域可以在视野树中被压缩到轴对齐的实体。
- 在游戏应用中,摄像机不会被允许在离几何体任意近的位置,那样会引起不希望得到的渲染效果。因此,我们可以压缩相邻的实心三维像素,甚至属于分开cell的空心像素,只要结果元素的尺寸没超过摄像机碰撞半径。
- 最后,我们可以识别并简化摄像机不能进入的区域中的三维像素组。这包括在墙壁内部和地形以下形成的cell。
Tiles
除了三维像素化调整参数之外,portal生成的过程也是自动的。然而,这需要一些时间来完成。这对希望内容迭代的预期来说是不方便的,而且浪费了美术和设计者的宝贵时间。内存占用同样需要关心。未简化的,高分辨率三维像素化可以消耗几个G的内存。
Umbra 3通过将游戏世界划分到空间上的计算单元tile来避免这个问题,tile可以独立于其他tile来计算。这样,游戏世界就可以通过一个个tile来并行计算或者分布式计算。只有当前的处理的tile集合需要高分辨率三维像素表示而占用一些内存。
因为portal的生成过程是确定的,一个tile的计算结果也可以通过哈希的输入存储。这个方法支持增量改变,只有场景的更新部分需要重新计算。计算结果通过网络也可以共享。在运行时,可见性数据可以以tile为单位加入流。
运行时portal裁剪
Umbra 3解决方案的另外一个组件是运行时遮挡裁剪算法。这个算法使用了简化的遮挡模型来决定摄像机视野内的可见性。
运行时裁剪算法需要是快速的——全部操作需要在几毫秒的数量级完成——来满足运行在60帧每秒的游戏中增值的需求。
因为处理的portal结构图数据量很大,算法设计中一个很关键的要考虑的地方是数据访问和缓存方式。特别是当硬件架构为流并行数据优化过的情况下,比如PlayStation3中的Cell处理器。
结构图遍历
自动生成的portal和cell结构图并不从根本上有别于传统手动生成的结构图。因此,我们可以准备使用传统的portal裁剪算法,递归遍历结构图,同时用视锥体拣选访问过的portal。然而,这类遍历必须对每个可见路径导向的cell,访问每个cell一次。在最差的情况下,这会导致指数级的算法运行时间和灾难性的性能表现。
为了限制cell的重进入数量,Umbra 3运行时裁剪算法以最广度优先的方式遍历结构图。软件光栅化被用于收集可见性信息到一个屏幕空间的遮挡缓冲,而不是几何体的portal解算器。这个方法几乎完全去除了不必要的递归。然而,给出通过初始格子立方体构建cell的方法,真正的广度优先cell处理顺序可能并不存在:结构图中的cell会有循环,没有其他选择只能处理一个cell超过一次。
为了缓解这个问题,结构图被储存为盒子形状的tile,每个都持有十几个到上百个cell。Tile通过这样的方式生成,简单的从前到后的顺序可以在tile之间被建立。每个tile的遍历同样使得结构图数据的访问是空间上连续的,因此缓存也很友好。
Tiling的优势就是一旦tile中所有的cell都被处理了,我们知道已经积累了它们最终的可见性信息,因此可以安全地释放用来捕获每个cell可见性的任何资源。
Portal光栅化
层次化的tile结构图遍历有助于管理任何时候激活的cell数量。另一个重要的内存优化是 遮挡缓存的数据排布。再一次,保守的正确结构需要提供成本有效的解决方案。Portal矩形光栅化到低的分辨率中,每次采样1个位,覆盖缓冲。缓冲中的每个设置位表示到cell的一条未遮挡路径。
光栅化空的空间(portal)而不是遮挡几何体代表,这个概念最初看起来并不正统。然而,光栅化变换后的quad允许简单保守的处理几何体边缘。光栅器对portal边缘采用半空间的测试,通过层次化细分屏幕矩形和测试矩形角上的像素,在大型室内或者室外区域节约了计算资源。保守的光栅化同样允许在运行时平台性能基础上的分辨率缩放。
Portal裁剪算法,包括遍历数据结构、输出深度缓冲、激活cell集合的覆盖缓冲,需要的内存总量,被固定在85KB。足够小到能够适应现代化的面向流的处理单元的本地内存。
遮挡测试
通过查找覆盖缓冲和对象的屏幕空间包围框是否有像素重叠,cell中的静态对象的遮藏测试可以在遍历结构图期间完成。
分配静态对象到cell在预处理阶段是很容易做到的,我们可以在三维像素表示时运作。然而,任何我们希望测试的动态实体会需要不同的解决方案。为了这个目的,裁剪算法需要在遍历时建立全局的深度缓冲。每个遍历过的cell的深度缓冲在当前覆盖缓冲的基础上更新,远距离的cell包围盒被用作深度写入值。在这个方法中,只要单一的16位深度缓冲需要在遍历期间被保留在内存中。
通过遍历来输出单一深度缓冲的能力使得在遍历后任何时间对动态对象进行遮挡测试变得可能。当确切位置和动画对象的范围在portal裁剪遍历的同时被确定时,这尤其重要。
图5:由遮挡数据生成的向下采样的深度缓冲。从左起:游戏场景中的视野内生成的颜色缓冲,渲染器使用的深度缓冲,最后,相当简化的遮挡视野,通过Umbra 3遮挡系统生成。
结论
考虑到游戏中展现的复杂度,确切的可见性信息是无价的资源。从特定视角确定元素是否可见就是遮挡裁剪。有很多方法已经被开发并用于解决遮挡裁剪问题。然而,每个传统方法都需要权衡,因此,遮挡裁剪仍有积极探索的空间。
Umbra 3遮挡裁剪系统就是设计来解决这些传统遮挡解决方案中权衡的问题。Umbra 3自动处理任何类型的多边形输入场景到一个压缩的运行时代理表示。这个代理可以被用作高效的保守正确的遮挡裁剪。关键方法是:
- 输入几何体在三维像素化处理时是离散的
- 运行时软件光栅化快速产出一组可见对象,以及在期望分辨率下的一个保守的深度缓冲
Portal结构图和运行时分辨率参数允许系统准确无误地从低端到高端设备之间缩放。因此,举例来说,Umbra 3对智能手机游戏来说,也是一个切实可行的解决方案。
总的来说,Umbra 3使得建立大型3D游戏世界,使用任意的多边形数据,而不需要对可见性有任何手动的工作,同时可以保证保守正确的裁剪结果。Umbra 3也使得可见性和空间查询信息可以被更多的游戏引擎子系统访问。因为如此,全世界的游戏开发者,诸如Buggie和其他许多厂商,在大量的产品中和广泛的运行时平台上使用Umbra 3。