延迟渲染是什么——重度渲染的优化手段之一

在欧美有着巨大人气的 FPS 游戏 KILLZONE 系列,作为开发小组的荷兰 Guerrilla Games 社,与那些开发最先端游戏引擎的 EPIC GAMES 、 CRYTEK 一起,走在业界技术领域的最前沿。该小组的最新作品 KILLZONE 2 不仅仅只是一款极具魅力的游戏,同样也成为了展现 PS3 特性的最佳舞台。

KILLZONE 2 在 2 月份发售后,就一直受到了非常高的评价,这一次就已在上个月洛杉矶举行的 GDC 技术研讨会中的内容为主题,分为前后两篇来介绍在 KILLZONE 2 中所使用的显示技术。

一般的 3D 游戏所采用的显示方法是,通过顶点处理 → 像素单位的阴影处理来进行的。如果非要将这个过程起上名字的话,那么就可以称为是向前渲染( Forward Rendering )或者画家算法。

在这个 Forward Rendering 过程中,图像引擎的渲染设置切换是以整个被演算物体来进行的,这样,像素渲染所得出的结果对于之后的距离计算会有很多无用的数据存在。导致了很多的渲染结果被废弃,白白的浪费了很多计算量。

另外,多通道渲染( Multi-Pass Rendering )中,也会有很多渲染由相同的几何多边形构成的场景的情况出现(等于是无意义的在重复这进行几何处理)。也就是说,使用 Forward Rendering 的话,经常会碰到在渲染过程中实际需要渲染的像素要比起画面所显示的像素多出许多或者是经常反复的重复计算同一物体的情况。

另外,需要将一个场景的渲染通过复杂的像素渲染程序进行并行操作的时候,只能让每一个像素渲染程序进行相同的计算,并且取他们的中间值来使用。如果这时正好碰到进行复杂的计算或者是纹理处理的情况,将会给 GPU 带来巨大的负荷。

在此,现在的人们也开始摸索着如何抛弃现有的 Forward Rendering 而使用其他技术。作为其中一个方法,就是最近开始流行起来的 延迟着色( Deferred Shading )技术。

左上为深度缓冲的内容,右上为像素矢量法线。左下为纹理色彩,右下为高光反射。将这些数值先进行渲染,随后在进行光照渲染的渲染流程就被称为 Deferred Shading 。

在延迟着色( Deferred Shading ) 中,场景内的多边形(几何)渲染过程是,首先原封不动的将有着重材质表现的像素渲染放到一边,让作为并行像素渲染程序所必要的中间值计算通过多个缓冲区进行先行的同时计算输出。此时起到关键作用的是从 DirectX 9 开始后具备的 多渲染目标 MRT ( Multi-Render-Target )特性。MRT 具有可在一条渲染流水线中的多个缓冲区内同时输出不同数值的功能,在 DirectX 9 中可以同时输出 4 个, DirectX 10 则是 8 个。

通过 MRT 进行多个缓冲区(纹理)同时输出的内容,根据图形引擎的不同可以有所不同,不过无外乎是, Z 坐标值,构成多边形的像素单位的法线矢量数据, 高光反射值,反射率(匹配纹理后的结果)等。只要使用 MRT 技术 , 就能一次将多个这样的数据写入到多个缓存区内。

随后,由之前得出的中间值在画面坐标系上进行后处理后,在来进行最后的像素单位的渲染。因为是将像素单位的阴影处理放在后面进行,所以他被称作为延迟着色( Deferred Shading ),顺便说一下的是,该方法提案者,是 Michael Deering 先生,他在 1988 年的 SIGGRAPH 1988 上第一次发表了这个技术。

作为 SONY 第一方软件商的杀手级作品, KILLZONE 2 被要求需要具备有 PS3 中最佳的画面效果。这样就必然的要走上大负荷渲染的道路,这也是渲染管线采用延迟着色的原因所在。

距离值(Z值,deps值) 镜头坐标系的矢量法线情报
镜面反射强度 高光强度
运动矢量 纹理色彩
Deferred Shading 渲染完毕后的效果 后处理完毕后的效果
延迟渲染是什么——实际应用与几何路径 (geometry path)

在 KILLZONE 2 上所应用的 延迟着色,大致的阶段可以分为 :

(1)几何路径(geometry path)(G-buffer 生成阶段)

(2) 光线路径(像素渲染)

最初的几何路径是指,先把重度像素渲染所进行的光照计算放到一边暂时不进行处理,随后对于场景内的全部多边形都采用普通的渲染。

PS3 所采用的 GPU 是称为 RSX 的 NVIDIA GeForce 7800 GTX 的简化版,因为是属于 DirectX 9 时代的 GPU ,所以能够并行进行 MRT 的数量为 4 个。对于 KILLZONE 2 的 Deferred Shading 的几何路径来说,在这 4MRT 上输出的内容就是如下图所示的 RT0 ~ 3 。

KILLZONE2 中的 Deferred Shading 中使用的 4 MRT 的详解,在 Deferred Shading 中,收录了这样多个数值的缓存我们将其总称为 G-Buffer。

首先,尽管是使用 MRT 作为输出格式,但是因为 PS3 RSX 的 FP16-64bit 缓存总线性能不足,所以必然就要选择整数 32bit 缓存 (RGBA8) 。接着是因为渲染的分辨率为 1280×720 。抗锯齿使用的是 NVIDIA 的 Quincunx 2×MSAA ,所以需要消耗 1280×720×(RGBA8×4+D24S8)×2×MSAA 合计 36.8MB 的空间。

开发小组认为这样的话还是顶的住的,所以就以此作为了标准。另外,4MRT 所输出的各个中间值缓冲区可以通过后面所说的后处理转换成低分辨率版后再利用。

那么,现在让我们再来按照顺利在看一看 4MRT 所输出的各个缓冲区( G  buffer )的内容吧。

距离 / 模板缓存是用来收录场景完成后场景距离的数值的。在之后进行光照计算时一但需要摄像机坐标位置,就可以对于这个距离值进行逆向计算来得出结果。

RT0 的 Lighting Accumulation Buffer(LAB) ,是在后期进行像素光照时需要用到的记录射入光线数据的缓冲区。在一开始的几何路径中, LAB 是用来输出光照图,以及用在 Light Probe (光探针)中模拟全局光照、环境光等所需要用到的数据。LAB 的 α 通道部分收录了 HDR 的亮度值 , 该值的范围为 0.0~2.0 。KILLZONE 2 的 HDR 是使用了 32bit 缓存来模拟 HDR 渲染。

RT1 是用来收录几何路径中,各个像素在摄像机坐标系中的法线矢量 x ,y 的数据。法线图的适用结果也被收录在此。为了让矢量法线的数值能够被正确的逆向计算(绝对值 =1 ) Z 轴的数据并没有被收录在此。具体可以用 z=√(1-x^2-y^2) 来求(因为 Z 的符号是绝对值,所以这样计算并没有什么大错误) 。

矢量法线 x , y 的数据形式是 16bit 浮点( FP16 ),这个时候 , 可以利用 NVIDIA GPU 特有的 unpack_4ubyte 命令来将 FP16 × 2 作为 32bit 整数缓存进行操作。

RT2 的 R 和 G 在 几何路径中是用来收录画面坐标运动的矢量数据( Motion Vector )。关于这个 RT2 的活用我们会在后面的动态模糊的章节里讲到。RT2 的 B 通道 和 α 通道中加入了有特定参数的镜面反射数据。其中的 B 收录了该参数的系数值与对数值 log2(n)/10.5 ,而 α 则收录了表示到底要进行多少强度的镜面反射强度值( Specular Intensity )

在 RT3 的 RGB 中则收录了适用于物件的纹理色彩数据 .RT3 中的 α 通道则收录了事先计算出的平行光源 ( 太阳光 ) 照射出的静态光影的渲染结果。

刚进行完毕几何路径的 Lighting Accumulation Buffer。这是仅仅只进行完静态光照渲染的画面。因为是测试画面的关系并没有用上纹理。

刚进行完毕几何路径的Lighting Accumulation Buffer。这是进行完动态光照渲染后的画面,因为是测试画面的关系并没有用上纹理。2张图的区别上,请大家注意阴影的不同以及影子的有无。

延迟渲染是什么——光线路径

光线路径是为了调和每一帧中高达 100 个以上(某些情况甚至会超过 300 )的动态光源与 10 个以上的会照射出阴影的光源相结合的重要过程。

Deferred Shading的光线路径,从处理方式的来看的话,给人以一种将光源渲染上去的感觉。

Forward Rendering 中的 3D 物体基准里是以 3D 物体是被什么样的光所照射的这一概念来进行光照 渲染 的,对于在 Deferred Shading 中已经完成好的 2.5D 映像,则由类似于图像处理的后处理来对于光源进行光照渲染。比如说,如果有 300 个光源的话,就要对画面进行 300 次后处理。

如果用比较抽象的话来说说明这个步骤的话,就是指给在几何路径中制作出来的那些未着色的物体来进行打光上色的这一过程。就算是有无数个光源被设置在场景内,也并不一定代表这些光源都会照亮其他物体。在 Forward Rendering 中,有不渲染那些着看不见的物体的方法,在 Deferred Shading 中,则有不计算那些对于其他物体没有影响的光源的这样一种优化手段。

另外,就算是会照射到其他物体的光源,也可以先计算到底照射到了画面中的多少个像素的面积,随后只对那些受到照射的像素进行光源渲染。因为点光源的照射范围是呈球状,所以对于这个光线照射范围的球体,对照着几何路径流程后的场景的距离( Z )值,在再其他 Z buffer 上进行进行渲染。

在阴影生成的方面,采用了一种和模板阴影方式相近的,光领域 (Light Volume) 渲染法来实现效果。通过渲染好的 Light Volume 来判断画面内到底哪些像素受到该光源的影响,随后在对此进行光照渲染。

从视点上来进行观察,相对于 Light Volume 的后部,位于前部的像素更加的受到注目。

从视点上来进行观察,我们可以看出,相对于 Light Volume 的前部,位于后部的像素成为了光照渲染的对象。
延迟渲染是什么——平行光渲染与阴影生成

动态光源可以用前面所说的 Light Volume 的方法来进行光照渲染,但是问题在于照射到整个场景的平行光源 ( 太阳光 ) 。就算是平行光源不移动,因为场景中的角色会进行移动,所以移动的位置或者是姿势都会导致阴影的变化。所以说,在光线路径下的光照渲染变得必不可少。

但是,如果是整个场景都被太阳光所覆盖的话就等于画面全体都被置入了 Light Volume (光照椎体)中。因此,游戏开发小组使用了特有的优化方法。那就是,通过几何路径生成 RT3 太阳光下的静止阴影数据。因为可以假定在这 RT3 里的阴影部分是不会被太阳光所照射的,被看成是太阳光光影渲染的范围之外,所以在光线路径中可以跳过这一部分的渲染。

进行完几何路径后被 RT3 所收录的静态阴影

也就是说,红色的这个部分并不属于太阳光光照的渲染范围 完成后的画面

在「 KILLZONE 2 」中的阴影生成,有在几何路径 RT3 内进行光照渲染的静态阴影与用于移动角色身上的动态阴影 2 种组成。

KILLZONE2 的阴影生成由深度阴影法与静态阴影相结合来完成的

通过颜色的不同我们可以在不同的位置看到被联合后的4张阴影贴图

另外,那些距离比较远的运动的物体,或者是那些有没有影子都不会去注意的物体,因为影响的范围非常的小,所以为了降低负荷,就省略了动态的光影生成。在动态阴影的生成方面,虽然是采用了非常普通的深度阴影(阴影贴图)法,但还是增加了很多独有的改良方法。

之所以要采用独有的改良方法一个是为了让阴影的质量上升,针对此采用了 4 张阴影贴图层叠的方法来对应视点和阴影之间的不同距离。每张阴影贴图所使用的深度缓冲最大可以为 1024×1024×16bit 。

而另一个目的则是,为了解决深度阴影法中边缘闪烁的问题。这个边缘闪烁是因为在视点移动的时候,用在阴影贴图里的深度缓冲会和视线矢量同步旋转而导致的。

就算是对象物静止不动,只要是视点发生变化的话,被阴影贴图所画上的范围也会发生变化,所以在最终的场景中阴影轮廓的边缘也会发生抖动。

在 KILLZONE 2 里为了改善这个现象,采用了地图坐标系中的阴影贴图里加上层叠的方法。通过这个方法尽管可以抑制住阴影轮廓的抖动,但是因为阴影贴图由此就变成了非固定的形式,所以在某些场合下会发生阴影的解析度降低的问题。

最里面 (LEVEL3) 不进行阴影处理 LEVEL2,可以看到静态的阴影 LEVEL1,静态和动态阴影都被渲染的出来
最前面(LEVELE0),这里的静态和动态阴影也都被渲染的出来 只有动态阴影 只有静态阴影

最终完成的画面

就算对象物静止不动,阴影贴图内的使用方法也会有变化 KILLZONE2 中通过 SPU 将 虚拟全局光照 ~ Light Probe 信息转换成曲面纹理
KZ2 中的 GI——通过 SPU 将 Light Probe 信息添至曲面纹理

在本世代的 3D 游戏显示中,那些具有最新技术的工作室基本都会在游戏中使用全局光照 (GI : Global Illumination) 这个技术。

在现实世界里,照明并不仅仅只局限于直接光的照射。被照射的物体本身也会成为一个发光的间接光源,从而产生物体之间互相反射的这样一种复杂的照明效果,这就是全局光照。特别是我们把对于相互反射的照明情况称作为 Radiosity (辐射度)。

基本上,现在的即时 3D 显示管线都是只能处理直接光的照射(不考虑是否有遮挡),所以不再 GI 上下点特别的功夫的话是不行的。只是,现在的 GPU 没有即时演算 GI 的能力,所以采用预先计算的方法基本上是主流。


将 Light Probe 可视化后的画面


l=0、1、2、3… m=-l~+l的球函数的3维可视图。比如说使用到I=3的第4层的话,将会总计有16个球函数被使用到。

在 KILLZONE 2 里,制作小组首先采用 Light Field 法对 GI 纹理进行离线渲染随后在作成光线贴图,这个时候,同时对于游戏中的场景以一定的间隔设置 Light Probe 。Light Probe 是来决定该位置的光线到底是怎么照射的一种道具。

光线贴图的生成以及 Light Probe 的计算,是将所有的静态光源设置完毕之后,需要花上一定的时间,在考虑到相互的反射等复杂的条件后在进行的全局光照计算。因此,各个 Light Probe 需要采取射向该位置的所有光线(复杂的全局光照结果)数据。

比如,天花板上有着白色荧光灯的狭小的房间里,左边的墙壁是红色的,而房间中心被设置了一个 Light Probe ,那么该 Light Probe 将会受到上部白色光线的照射,而左边则要采取到柔和的红色(受到荧光灯的照射后红色墙壁的反射光)。

在进行即时渲染时,以该 Light Probe 所采取的光量的情报为基准,来对该场景内活动的角色的光照渲染。再将被渲染出来的角色与实现计算好的全局光照结果的光线贴图进行调和。这样,因为当角色运动时,就会受到不同的 Light Probe 的光照的反射,这就正好达到了连场景中受到间接光反射的都考虑到的光照渲染过程的这一要求,从最终的结果来看,完全不亚于那些进行及时演算出来的 GI 效果。

在 KILLZONE 2 中,每一个场景大约需要事先安置 2500 个 Light Probe 点,各个 Light Probe 中存有将 球函数的 I=2 之前的 9 个数据通过 RGB 3 元素作为 K-D 树的数据。简单的来说就是类似于放射状的能源分布图一样的方便的函数。如果将其可视化的话就会和下图中显示的一样。从概念上来说,放射状的数值分布可以通过几个 均值系数来进行近似再现,也就是类似于 MPEG 或者是 JPEG 这样的不可逆的压缩方式。

在索尼克 WA 这个游戏中所使用的 类似于 Light Probe 的数据中记录着 8 个方向的离散值,但是在 KILLZONE 2 中则记录着 9 个 球函数 . 在实际进行即时渲染时,读取相邻的 4 个 Light Probe 中的球函数,从中将 Light Probe 的全方位光量进行解码随后在一次作成一个 8×8 的 纹理元素的曲面纹理(球面坐标系的全方位纹理),当然这也仅仅只是读取出相近的 4 个 Light Probe 的数值随后进行加权平均的插值计算而已。

读取相近的 4 个 Light Probe 的值随后进行球函数的转换

计算出从各个方向照射到该角色身上的环境光

以此数值来生成 8*8 纹理单位的曲面纹理

听上去好像是一个负荷挺高的计算, 在 KILLZONE 2 里,该处理则是全部交给 SPU 来进行运算的。根据开发小组公布的数据, 1 帧中大约需要读取 600 个 Light Probe 的数据,这一连串的处理的负荷大约需要消耗掉一个 SPU 中的约 13% 的处理能力。

在实际的像素渲染中对像素单位进行光照处理是以各个像素的矢量法线数据为基础,将这个曲面纹理作为样本以它的值来作为环境光进行光照处理。

之所以要读取近 600 个的 Light Probe 数据,是因为在 KILLZONE 2 中角色的身上的各个部位(入角,身体,手等)的细小的地方都有使用到曲面纹理。这样我们才能够看到那些诸如上半身和下半身被不同的间接光所照射的真实的效果。

在索尼克 WA 里,首先先要决定好角色的重心抵消的值,随后在加上光场。因为索尼克 WA 中的角色是 Q 版的角色,所以可以将角色作为一个固定的物体来进行操作,并不需要做的非常的细致。但是在 KILLZONE2 中因为角色是非 Q 版的人类,会有站立,蹲下,挥手等让人物上下左右变化的动作,所以才需要做到如此的细致。

再运动中的角色(物体)上加上白色的测试截图,在这个场景里,只有地板是属于静止的物体。 只渲染运动中的角色(物体)通过 Light Probe 被照射到的环境光以及太阳光(平行光)后的画面。 最终画面
总结——延迟渲染非常适合 PS3 ?

在 KILLZONE 2 的讲座的前篇中,我们以 Deferred Shading 为中心进行了细致的解说。Deferred Shading 看上去是一种非常绕圈子的渲染方法,但是却有着不受到运动角色的数量以及场景复杂的的影响,以及可以实现动态光源光照渲染的可扩展性这两个优点。

简单来说就是,例如, Forward Rendering 中有 100 个角色被 4 个光源所照射的话就需要进行 100 × 4=400 次的光照计算,但是如果采用 Deferred Shading 的话,首先可以将 100 个角色的几何数据跳过光照直接进行渲染,之后在将渲染好的 4 个光源进行光照处理,这样的话就只要进行 4 次光照计算就可以了。而且也可以根据负荷来调整光照计算时候的光源的数量。

在 Forward Rendering 中,就算是仅仅只改变动态光源的数量,也需要改变在 shader 中的参照函数的式样,就算是进行具有相同特征的光照计算的 shader ,也必须切换到其他类型的 shader 中,不影响到现在已经很复杂的 可编程像素着色引擎结构这一点也是一个很大的优点。

再那些需要表现出丰富的阴影效果的游戏里,采用 Deferred Shading 技术的例子越来越多也正是因为这个优点有着很大的效果。现在采用 Deferred Shading 技术的 3D 游戏有「 Bionic Commando 」 (CAPCOM) 、「 S.T.A.L.K.E.R. 」 (GSC Game World) 、「 Tabula Rasa 」 (NC soft) 等,可以想象,今后必将会有越来越多的游戏也采用这个技术。

顺便要说下的是,也有一种说法是 Deferred Shading 技术并不适合于 XBOX360 。原因在于,为了弥补 XBOX 360 的 GPU 的带宽不足而采用的 10MB EDRAM 。在 XBOX360 中的高分辨率帧,或者是在 MRT 上进行超过 EDRAM 容量 10MB 的高负载渲染的时候,必须将每次渲染的容量分割成 10MB 以下依次进行。

在进行 Deferred Shading 的时候,需要在几何路径中输出整个画面的中间值,比如说 1280×720 4MRT 的情况下,就算是不包含有距离缓存的情况下就已经需要消耗掉 14MB 的显存,这个数值远远的超过了 10MB 。就算是分成 7MB×2 来进行 2 步渲染,在进行第 2 步渲染的时候,必须要清除第 1 步渲染的结果。和进行一次渲染相比会更进一步的消耗内存总线的资源,从而影响到性能。尽管 XBOX360 并不是不能采用 Deferred Shading 的方法,但是相比较起来该法还是比较适合 PS3 以及 PC 。

当然, Deferred Shading 也是有弱点的。首先被指出的就是没有一种很有效率的方法来处理那些半透明的物体。在 Deferred Shading 中,尽管有着对于半透明的物体使用 Forward Rendering 这一很有创意的解决方法,但是对于半透明物体多的场景来说,则无法发挥出 Deferred Shading 的效能。只是,对于在 GPU 性能上有着先天缺陷的 PS3 来说, Deferred Shading 仍然是一种非常有效的处理手法。想必该方法将会被越来越多的用在今后的 PS3 独占游戏中吧。

KILLZONE2 的游戏规格与活用 CELL 处理器的方法

KILLZONE2 是随着 PS3 一同在 2005 年的 E3 展上公布的。当时预定的发售日期为 2008 年(欧美),而实际开始制作的时间正好也是 2005 年,就是说大约花了 3 年的开发时间。在制作的高峰期,开发人员除了本社内的 140 人外,还有 SONY 系外包公司的约 50 人参与了制作,整个周期平均的开发人数大约在 120 人左右。游戏的主程序员有 27 名,其中,最多的为游戏内容设计部分 9 人。接下来是图像显示部分 7 人,AI 设计 6 人,网络关联部分 5 人。


KILLZONE2 开发小组回忆到: SPU 真的是一匹很难驾驭的骏马啊

在整个开发过程中,最困难的部分,莫过于作为 PS3 的 CPU CELL 中的 128bit SIMD RISC 处理器 SPE ( Synergistic Processor Elements ,SPU 是指 SPE 内部的运算核心,人们通常将 SPE 和 SPU 画等号,在 Guerrilla Game 的资料中也将其称为 SPU 所以下文我们就按此资料统一将其称为 SPU )的运用了。

PS3 中除了作为主 CPU 的 3.2GHz PPE ( Power Processor Element )外,另外以 3.2GHz 频率进行工作的 6 核心的 SPU 也可以被游戏程序进行充分的利用。但是在游戏的开发初期,因为缺少关于 SPU 的信息,导致开发陷入困境。SPU 尽管可以算入通用处理器的类别里,但是在当时却没有能够使用的程序库( library ),使得编写能发挥出 SPU 威力的程序几乎不可能。

当然,不管怎样,经过了千辛万苦。开发小组终于设计出了面向 SPU 共计 44 种程序。最具有代表性的有以下几种。

  • 动画
  • 危险预测 AI
  • 弹道回避 AI
  • 障碍物规避 AI
  • 冲撞判定
  • 物理演算
  • 粒子计算
  • 粒子渲染
  • 场景图( Scene graph )
  • 生成绘图列表
  • 光源基准图像渲染扫描计算 (IBL Probe)
  • 图像后处理
  • 动态音乐播放系统的控制
  • 关节平滑处理
  • MP3 解压
  • Playstation Edge 内的解压处理 (Zlib)

从可以称得上是最基本的处理方法的关节平滑处理 和粒子处理着手开始对 SPU 程序进行应用,但是反过来也有一些没有被采用的程序,比如说流体模拟,不采用的理由是效果看起来并不是非常的好的缘故。游戏的基本 帧速率 是 30fps。在每一帧中 SPU 的计算量如下。

  • 物理演算为每帧 100 个物体
  • IBL Probe 的生成最大能达到 600 个
  • 光线投射( Ray-Casting )最大数量为 250
  • 最多 200 个的动画样本
  • 最多 250 个的粒子处理
  • 最多 6 个场景图的衔接
  • 最多 2000 个显示物体的绘制
  • 最多可进行 75 个关节圆滑处理

通过上面的数据,我们不但可以得出 PS3 的真实的性能规格,还可以将其作为了解那些最新游戏的处理负荷发展的重要情报。下图为在开发中的画面,可以看出,当前画面的负载情况。


表示 CPU 负载情况的调试监视画面

中央区域表示了 PPU (上部)和 SPU (下部)的负载情况,因为截图的关系只能看到 PPU 的显示条。右侧显示的则是 SPU TIME ,每一列进行详细说明的话,从左边开始为运行的工作名,工作数量,以及每秒 30 帧内所占有的时间。就算是在过场动画的环节里,总工作数量也会达到近千个。当然,因为不需要对 AI 和玩家的控制进行计算,所以负载约为 1.5 个 SPU 左右。而在进行游戏的时候,负载则经常会是 4 ~ 5 个左右。

通过 SPU 运行的 KILLZONE2 智能 AI 程序

当某些 PS3 游戏的开发人员还在头痛该如何活用 CELL 的核心的时候,KILLZONE 2 则已经通过 SPU 来实现敌方的 AI 逻辑运算。而且,实现的还是对于现在的 3D 游戏来说属于比较高等级的推理型 AI。也可以称得上是一种创举吧。

KILLZONE2 的场景地图是以导航点为基础而构建出来的。给人以一种将可以移动的场所作成一个表结构然后通过网络来相连的印象。敌方与我方的 NPC 角色将这看不见的节点作为一种转折点,在一张看不见的蜘蛛网里进行运动。

在每个场景中,有着数千个的导航点,每个导航点中包含有记录着在该导航点上能够看到的全方位的场景距离值的低分辨率的环境贴图。这就是非常具有创新意义的一点。该环境贴图并不是用来进行显示绘图用的,而是为了表现出导航点周围空间的广阔程度,更进一步说的话是作为直接表现出遮蔽构造的数据来让 AI 进行使用。

开发小组将该环境贴图称为 Cover Map ,该图是通过离线计算而生成的。图具体的分辨率并没有公开,但是距离值是被压缩到 6 bit 后记录下来的。从公开的画面进行放大浏览的话,可以看到是一个 16×16 像素 ×6 面的样子。不管怎样,为了能够让只有 256K 缓存的 SPU 进行方便的操作,该数据的体积一定是进行过一定的压缩的。


白色表示附近有遮挡物,黑色表示该区域属于开放区域。红色则表示现在自己所在的位置


白色表示附近有遮挡物,黑色表示该区域属于开放区域。红色则表示现在自己所在的位置

具体的来说,让我们假设,玩家的角色正躲在遮挡物的后面,这时 KILLZONE2 的 AI 将如何反应呢?在这种情况下我们希望 AI 的反应因该是,AI 开始推测玩家所在的位置,随后向玩家所在的位置,进行威吓射击,或者是预测玩家下一次出现的位置,向该位置进行提前攻击,以及进行伏击等等。

KILLZONE2 的 AI 会记住什么时候,在哪个导航点上遭遇玩家。随后根据过去和玩家遭遇的位置的导航点上推测玩家像哪个导航点移动。如果说该导航点是属于 AI 的可视范围的话就会排除该导航点。这是因为,会碰到明明是可视范围却看不到玩家的这一伦理上的矛盾。由此 AI 会不断对玩家从原来的位置移动到了那个导航点来进行预测。

AI 的探索范围有一个阀值来进行限制,以防止搜索过于广阔的面积。另一方面,如果 AI 探索到的范围过于狭小,导致 AI 的移动被束博住的话,AI 会自动转入各角色的自主行动模式。例如,原地待机并继续发动攻击,或者是不断的进行搜寻直到发现了玩家的位置为止。

这样的 AI 动作,我们将其可视化后就像下图一样。下图中在楼上的玩家正和楼下的敌方 AI 进行对峙,而玩家则正隐藏在楼上一掩体后面。敌方的 AI 开始以最后一次受到攻击的场景为中心(这次的例子正好该场所是玩家正隐藏着的掩体),开始搜索玩家可能移动到的导航点的位置。而从敌方 AI 视角上看不到的导航点,因为无从得知能否前往该导航点所以则不对其搜索。

另外,在 KILLZONE2 中。在场景状况没有发生变化,对于敌方的 AI 来说威胁已经消失的情况下,为了进行下一步的动作,SPU 将运行一种威胁预测( THREAT PREDICITION )的线程,而 SPU 通过此可以最多计算好接下来的 4 个行动步骤。在这个例子中,通过预测搜索玩家下一步的移动方向与前面所述的 Cover Map 的参数进行结合比较的结果,敌方的 AI 决定对于掩体的断开部分,也就是图中黄色的导航点的位置进行威吓射击。


楼上的玩家躲藏在遮挡物后和楼下的敌方 AI 进行对峙的场景


KILLZONE2 的敌方 AI 采用的是推测型 AI。
实际进行对抗时可以感受到 AI 那充满智慧,非常类似于真人一样的行为。

防止被友军误伤的回避 AI

对于想 KILLZONE2 这样时常会发生近距离交火混战的 FPS 游戏来说,经常会碰到的一个问题就是玩家或 NPC 的误伤问题。例如,如在玩家射击的时候正好有我方的 NPC 站在射击线,从而导致误伤的情况发生。又或者是,对于正在向这边开火的敌人,本方的 NPC 掩护玩家向敌方进行射击,但是却误射中了玩家的背部等。

这种种现象都是因为本方的战友们互相遮挡了对方的 射击线而导致的问题。KILLZONE2 中的友军 AI ,会事先考虑到那个导航点会遮挡住友方射击线,随后在决定移动的位置。具体的流程为,事先将属于我军的各火力点的射程范围内的导航点标记上“危险”的记号,随后在移动选择导航点时将这些导航点排除在外。

在 KILLZONE2 中,敌方的 AI 并不是游戏中类似于“神”一般的存在,各个 AI 角色都基于即时推理程序来进行行动是本游戏 AI 的一大特征。不是完全的随机行动,也不是那种能够预测到敌方动作的作弊行动,而是采用一种和玩家进行交互式的行动方式,使得玩家能够真真切切的感受到敌方 AI 行动的真实感和智慧感。

在 KILLZONE2 中,表示遮挡物和掩体等的 Cover Map 就是预先生成的。在这个 Cover Map 中,如果能够即时的演算出敌方角色的视点的话,就能够像最先进的带有摄像头的自律行动性的机器人那样,进行更加智能化的行动。但是,就算是具有 SPU 的 PS3 也无法实际运算如此高等级的 AI 程序。当然,想必今后总有一天,会有搭载上这样高级 AI 程序的游戏来到我们面前吧。


楼上有 2 名队友,楼下则是敌方的场景


从楼上 2 名队友的立场来看,是要对楼下的敌方进行射击。
图中的橙色和黄色表示出了他们的射击范围。


在这个盒状射击范围内的导航点就被认做为容易受到误射的危险地带

通过 SPU 来进行粒子计算

就算是 30fps 的 KILLZONE2 ,粒子系统也是非常占系统资源的存在。1 帧中的负荷,评价下来,最多要运行 250 个例子系统,其中有 150 个左右要被绘制出来。在 1 帧中,最多会有 3000 个粒子存在,其中最多需要同时计算 200 个左右的粒子碰撞情况。

在 KILLZONE2 中,粒子系统最初是通过 PPU 来运行的,但是实际效果却非常的慢。粒子系统对于那些多核 CPU 来说简直就是噩梦一般,就算将程序多线程化后,该线程仍然会频繁的对内存进行连接。这样的话就会引发缓存 系统失效从而导致性能大幅度的下降。因此,开发小组决定化时间,将最初在 PPU 上执行的粒子系统移植到 SPU 中执行。

首先在第 1 个月中将粒子的顶点生成移植到了 SPU 上,随后的第 2 个月将粒子的虚拟核心移植到了 SPU。在第 3 个月中制作组优化了粒子系统的数据等级,最后的 1 个月,则对内存分配等进行了优化。最终的结果是,几乎所有的粒子系统都从 PPU 移植到了 SPU 上,基本上整个粒子计算都由 SPU 来完成。仍留在 PPU 上和粒子系统相关联处理只剩下了 绘图时所需要的场景汇总处理以及音效控制等。

粒子系统移植到了 SPU 后,效能得到了显著的改善,其最大的原因莫过于在单位时间内可以处理的粒子量得到了大幅度的增加。另外,在 SPU 上运行的粒子系统可以对 SPU 的 256KB 本地缓存进行局部的操作也是另一个很重要的原因。SPU 的程序可以在 256KB 本地缓存内进行操作基本上就等同于普通的 CPU 有了很高的缓存命中率。读取主内存中的数据也是通过各个 SPU 的 DMA 来进行的,就算某个 SPU 在等待数据的到来,别的 SPU 上运行的粒子系统也可以在本地缓存内进行处理运算,这样就实现了整体的并行计算。

托在 SPU 上运行粒子系统的福,PPU 的间接开销( overhead )被降低到了只有原来的 1/20 ,也就是说,PPU 的负载被大幅度的降低。和其他游戏相比 KILLZONE2 大概要处理普通游戏 3 倍的粒子数量。


粒子数量众多的 KILLZONE2 的粒子特效,其实现的秘密就在于通过 SPU 进行运作的粒子系统


粒子数量众多的 KILLZONE2 的粒子特效,其实现的秘密就在于通过 SPU 进行运作的粒子系统

KILLZONE2 中的后处理也通过 SPU 来实现

作为 PS3 GPU 的 RSX ,其本质就是一块 NVIDIA GeForce7800GTX 的简化版,理所当然的是 RSX 并不属于统一着色架构。更进一步说的话与采用了专门为家用游戏机设计的,使用了统一着色架构的 Xbox 360 的 GPU 相比峰值性能要稍差一些。但是,PS3 有着 CELL 这块处理器,将 GPU 上的差距通过 SPU 来进行填补,成为了今后在 PS3 游戏显示处理上的一种趋势。


KILLZONE2 中,通过 PS Edge 来进行顶点动画处理

不过,人们通常使用的方法是通过活用由 SCE 提供的 中间件 「 Playstation Edge 」 (PS Edge) ,通过 SPU 来弥补 RSX 顶点着色的性能不足,在 KILLZONE2 中也使用了 PS Edge ( Inverse Kinematics ,反向运动学的处理采用了独自设计的插件),基本上将所有的顶点动画处理全部交由 Edge Animation 进行处理。30fps 的画面中,会有 40 个动画工作要进行,最多有 200 个左右的动画要成为被参照的对象。另外,在一个人体角色上会进行大约 2 ~ 50 个动画的混合处理。

从性能上来说,1 个 SPU 的负载率在 12% 以下就可以完成了,比起在 PPU 上进行处理,处理时间缩短到了只有原来的 20% ,单纯的进行计算的话,通过 SPU 进行处理会比 PPU 要来的快上 5 倍。

在 KILLZONE2 中,并不仅仅只是让 SPU 来帮助处理顶点着色,作为辅助像素着色也就是我们常说的后处理也是通过 SPU 来运行的。具体的代表有以下 3 种形式:

  1. HDR 渲染的高亮部分的溢出处理( BLOOM 处理)
  2. 运动模糊
  3. 景深 (DOF:Depth of Filed)

后处理,简单来说就是对于渲染完毕的图像通过像素着色进行图片再加工的一种处理手段。这样的处理,RSX 当然也是能够办到的,但是 KILLZONE2 的开发小组根据以往的经验来判断,后处理的过程会占用整个 RSX 大约 20% 的处理时间。所以开发小组认为通过 SPU 来进行后处理能够实现更好的性能。

在 KILLZONE2 中,开发小组将一部分的后处理移植到了 SPU 上进行运作,而空余下来的 RSX 的处理时间,则能够进行其他的一些渲染处理。具体的处理流程如下:

  1. 首先由 RSX 渲染出低分辨率帧随后放入主内存中( XDR )
  2. RSX 将数据写入 SPU 中
  3. SPU 进行后处理的操作
  4. RSX 已经再渲染下一帧的画面中
  5. 将 SPU 进行后处理完毕的结果传输回 RSX。RSX 暂停现在进行的帧渲染操作,将后处理的结果和原数据进行匹配,随后输出最终的画面

为什么 SPU 进行后处理的是低分辨率帧呢,制作小组给出的情报是因为 SPU 没有能力处理完整的帧图像。而且,因为像上面所写的 3 种形式的后处理,反正也只是一些模糊之类的效果,并不需要高分辨率来进行。想必这也是用低分辨率帧的原因吧。


比起由 RSX 来进行后处理,使用 SPU 不管是在效率还是在质量上都来的更加优秀

图表显示了在 30fps 运行时,仅依靠 RSX 进行后处理与 RSX+5 个 SPU 进行后处理时负载的区别。从结果中我们可以看出将后处理的一部分移植到 SPU 上进行操作后,大约可以降低 6% 的 RSX 的负载。从占用的处理时间来看比起单独由 RSX 来执行,通过 SPU 进行执行更来的核算。通过 RSX 和 SPU 的并列运行,使得 RSX 的负载下降,可以说得出了一个非常令人满意的结果。而且,比起单独有 RSX 运行来,并行运算的后处理的品质,要来的更加的高。这也可以看出由 SPU 进行运算时的运算精度要来的更加的高。

通过 SPU 来进行的后处理

Bloom

开发小组首先在 SPU 上执行的是被用来实现 HDR 渲染效果的 Bloom 效果。首先抽取出 1/4 分辨率下生成的结果帧的高光部分,随后在生成 1/8 ,1/16 ,1/32 ,1/64 等更低分辨率的高光部分的帧,随后在各自对应进行 7×7 16bit 固定精度的高斯模糊滤镜处理。将 1/4 ~ 1/64 大小的处理结果通过 α 合成 buffer 输出。另外,在模糊高光部分时同时也会读取它的距离值,如果有遮挡物的话,则会对于溢出的效果进行一些限制。最终运行的结果,SPU 被分配到的计算量大约为 13.1% 左右,在实际运行时会有 5 个 SPU 参与工作,这样平均被分到每个 SPU 上的计算量大约为 2.6% 左右。

动态模糊

在 KILLZONE2 中,动态模糊的后处理也是通过 SPU 来实现的。将 1/4 分辨率的渲染结果作为后处理的数据。随后在使用通过由缩小到 1/16 的画面坐标系基础所换算出的运动矢量 (Motion Vector) 缓存。基本上和 CRYSIS 中所使用的 (OMB) 技术相同。1/16 分辨率的运动矢量缓存拥有每个像素在画面上是向那个方向移动的 2D 情报。这样可以通过前面一帧中各个顶点的位置和现在这一帧中各个顶点位置的区别来得到各个顶点的速度数据,在以此数据为基础,转换为从视点所看到的各个像素单位的速度数据输入纹理进行生成作业。另外,在玩家进行高速运动的时候,为了防止整个游戏画面都模糊成一片,静态物件被排除在运动矢量的计算对象之外。也就是说,有模糊效果的,只有那些动态物件。

动态模糊是依据这个运动矢量缓存的值来进行计算的,但是如果只是以此来运算的话,因为动态的值偏小所以会导致整体画面的魄力不足。在此和 CRYSIS 一样,对于运动矢量缓存的数据进行了扩张处理。

用该扩张版的运动矢量缓存的数据来对 1/4 分辨率的渲染结果进行处理。进其中进行模糊滤镜处理的则只有 8 个样本点,并没有像 CRYSIS 那样进行 Ping-pong Blur 的处理。关于这点,开发小组表示:尽管这样的话会变成粒子比较粗糙的模糊效果,但是在游戏中,这样的效果已经足够了。

将 1/4 分辨率的模糊图像和 1/4 分辨率的原始图像进行合成时是以运动矢量值的 α 值为基准进行的。也就是说因为基本没有运动的部分的 α 值为零,所以这是一种通过透明方式来进行合成的绘图方式。最终运行的结果,SPU 被分配到的计算量大约为 9.5% 左右,因为实际会有 5 个 SPU 参与工作,这样平均被分到每个 SPU 上的计算量大约为 1.9% 左右。


1/4 分辨率的渲染结果


1/4 分辨率的纹理缓存


1/4 分辨率的运动矢量缓存。实际处理时将会被缩小到 1/16

景深

开发小组最后在 SPU 上运行的是模拟景深的后处理程序。当然首先也是将 1/4 分辨率的渲染图像输入,随后得出 1/4 分辨率的距离缓存。从实现的手段上来说,通过虚拟的摄像机,给予被捕捉到的场景的焦点距离以一个开口率,和对焦距离值的差别越大就越有景深的效果。比较新颖的地方在于,该模糊滤镜通过 SPU 采用了由 36 点来构成的一个圆状的样本点。而且并不仅仅是因为 36 个点的数量的多,连计算也是由浮点小数精度来进行的,这样就可以得到非常高的样本质量。焦点的偏差越大模糊圈也就来的越大,为了不让效果来的过于夸张,模糊圈的半径被限定在了一个范围内。

另外,为了防止程序无视前景和后景之间的关系,导致模糊的效果渗出,制作组采用了首先读取距离情报,随后在从后向前取样,最后在从前往后进行混合的这样一种复杂的取样方式。能够实现这一复杂的取样方式,也要多亏了有 SPU 才能够实现。

最终的效果表明,SPU 需要负担的计算量大约为 23% 左右,在被分配到 SPU 中进行计算的后处理效果中属于负载比较高的特效。在实际运行是会有 5 个 SPU 参与工作,这样评均被分到每个 SPU 上的计算量大约为 4.6% 左右。

最初开发小组曾经担心过景深效果能否在 SPU 上被顺利的执行,但是实际运行的结果,比起当初在 RSX 上进行双线性取样处理来性能上要强上很多。所以制作小组最终认为让 SPU 来进行景深的后处理可以说是非常的成功。


1/4 分辨率的渲染结果


通过 SPU 进行 BLOOM ,动态模糊以及景深特效后的截图


将后处理结果与全分辨率的渲染结果进行合成后的截图

总结,SPU 拯救了 PLAYSTATION3

PS3 发售至今已经过去了 2 年,我们有一种“啊!终于开发商能够很好的活用 CELL 芯片的能力”的感觉。而且,PS3 独占作品的开发人员也开始感受到了 SPU 那无限的可能性。

在这灵活运用到 SPU 能力的 KILLZONE2 中需要注目的 2 点是,1 是将 3D 显示的后处理移植到 SPU 上进行运行。后处理是一种非常消耗填充率的特效,通过让 SPU 来进行后处理的辅助,可以给填充率性能不足的 RSX 以很大的支援。

3D 显示的渲染流程,粗略的来说的话就是 顶点处理 → 像素处理 → 后处理。现在 PS3 游戏已经渐渐的形成顶点处理交给 SPU ( PS Edge ),后处理也交给 SPU 的风潮。反过来看的话,我们也可以看出,RSX 仅仅用来做像素着色这一步,真可谓 30 年河东,30 年河西啊。

第 2 点则是在 SPU 上运行的 AI 程序。尽管有着传统的导航点为基础,但是将具有自主行为和威胁预测的 AI 程序通过 SPU 进行运行,而且是通过多线程技术,运用到敌我双方身上,可以说是一种非常先进的技术。将这样的智能 AI 设计运用到 Xbox 360 上,应该是非常困难的一件事情,这也可以说是 PS3 游戏看得见摸得着的优点吧 .

PS3 的 GPU RSX 现在说不定已经成为了一种累赘般的存在也说不定,SPU 在今后的将来应该还会做出更多的贡献。PS3 游戏的未来被也许取决于 SPU 的活用上吧。

KILLZONE 2 显示技术详解相关推荐

  1. 《Hadoop技术详解》一导读

    前 言 Hadoop技术详解 本书采用的约定 本书采用以下排版约定. 斜体 用于表明新的术语.URL.电子邮件地址.文件名和文件扩展名. 等宽字体 用于程序清单,正文段落中有关的程序元素,如变量及函数 ...

  2. Qtum量子链研究院:Plasma技术详解(下篇)

    Plasma的设计模型有两个主要的分支:Plasma MVP(Minimal Viable Plasma,最小可行的Plasma)和Plasma Cash.Plasma MVP的目标是为最基本的可用的 ...

  3. 视频直播技术详解(8)直播云 SDK 性能测试模型

    <视频直播技术详解>系列之八:直播云 SDK 性能测试模型 牛小七2016年10月12日发布在 视频直播技术详解 七牛云于 6 月底发布了一个针对视频直播的实时流网络 LiveNet 和完 ...

  4. 技术详解:基于人脸识别的 AI 弹幕

    --------点击屏幕右侧或者屏幕底部"+订阅",关注我,随时分享机器智能最新行业动态及技术干货---------- 有时候,弹幕比剧情还精彩,那些脑洞大开.观点鲜明的弹幕,可以 ...

  5. 《视频直播技术详解》系列之八:直播云 SDK 性能测试模型

    七牛云于 6 月底发布了一个针对视频直播的实时流网络 LiveNet 和完整的直播云解决方案,很多开发者对这个网络和解决方案的细节和使用场景非常感兴趣. 结合七牛实时流网络 LiveNet 和直播云解 ...

  6. H.264/AVC视频编解码技术详解 第一章 视频信息与压缩编码

    H.264/AVC视频编解码技术详解系列笔记 是对 H.264/AVC视频编解码技术详解 课程的学习 文章目录 人与世界的交互 视频信号的表示方法 视频压缩编码 视频信息为什么可以被压缩? 视频压缩编 ...

  7. ×××技术详解(全)

    ×××技术详解(全)   一.引言   <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office ...

  8. 15、Windows驱动开发技术详解笔记(11) 基本概念

    9.Windows驱动程序的入口函数规定为_DriverEntry@8,所以用C++编写时要用extern. 驱动程序中,不能使用编译器运行时函数,甚至C语言中的malloc,C++的new函数都不能 ...

  9. Keras深度学习实战(3)——神经网络性能优化技术详解

    Keras深度学习实战(3)--神经网络性能优化技术详解 0. 前言 1. 缩放输入数据集 1.1 数据集缩放的合理性解释 1.2 使用缩放后的数据集训练模型 2. 输入值分布对模型性能的影响 3. ...

最新文章

  1. 02. 值类型和引用类型的传递
  2. 【MM模块】Batch 批次管理 2
  3. UGUI_不规则按钮的响应区域
  4. CodeForces - 553C Love Triangles(二分图)
  5. php 迭代器迭代中文时重复,3种方式解决iterator迭代器并发修改异常
  6. mongodb一致性协议_mongo的怎么保持事物的一致性-问答-阿里云开发者社区-阿里云...
  7. 云服务器怎么设置域名,云服务器域名设置在哪里
  8. 基于携程游记的出行领域顺承事件图谱项目
  9. 萌新的Python练习实例100例(二)根据企业的利润,计算企业的方法奖金
  10. 拉普拉斯算子属于卷积方法吗_论文笔记 - 图卷积神经网络综述
  11. Phenotips 项目源码分析 [0]
  12. Search in Rotated Sorted Array leetcode java
  13. SpringCloud实战(一)基于nacos实现订单+视频服务的调用
  14. 计算机主机电源排线怎么取,电脑电源的线怎么接? 机箱电源线接法图解
  15. Centos7固定内网IP并允许访问外网
  16. 单独备份config配置文件 (来自老梁邮件)
  17. 【SDOI2013】项链 题解
  18. Problem K: 三角形数
  19. Java 按照拼音首字母排序
  20. Android 活用RecyclerView分割线

热门文章

  1. android opengl es 圆锥纹理贴图
  2. 解决java “错误:编码GBK的不可映射字符 (0xBD)“原创
  3. 获取猫眼电影所有城市信息
  4. Linux下Redis安装与配置 (yum 软件源下载安装)
  5. 还在用Swagger?我推荐这款零代码侵入的接口管理神器
  6. 股票python量化交易016-计算最大回撤
  7. 【项目总结】电厂安全培训管理系统总结
  8. 论文:TransVG: End-to-End Visual Grounding with Transformers
  9. 基于深度学习的YOLO目标检测研究-附Matlab代码
  10. 基于51单片机的贪吃蛇小程序(8*8LED点阵实现)by_jy