当年第一眼看到MGS4的游戏视频就震精到,SNAKE隐身融入到背景里去的画面至今难忘(可惜这篇讲座里没有讲解隐身这部分的技术),现在有幸找到了这篇讲座的译文,果断的转载过来,并且把图片也替换成原文里的大图,在这里感谢译者。
揭秘开发人员的最优化成果,PS3最高端图形开发的秘密 翻译:胡文杰
会场:KONAMI东京会社
2008年的PS3游戏中带来最大话题的无容置疑便是METALGEAR SOLID 4 了。
作为PS3的标志性的作品,关于MGS4的各种开发秘密,小岛工作室在游戏开发者论坛“CEDEC2008”上积极进行了开发信息的公开展示。
本次连载中,我们基于CEDEC2008中发表的信息,结合在小岛工作室追加取材来的信息,希望向大家介绍并解说在MGS4的游戏图形中使用到的技术。
作为前篇,我们先介绍MGS4的基本图形特性及在MGS4中采用的特殊渲染管线。
■ MGS4的游戏图像机能
SNAKE的POLYGON数大约增加了3倍
协助我们这次取材的是小岛开发部的高部邦夫制作部程序组技术总监和是角有二制作部程序组经理兼主程序。高部是CEDEC2008中在MGS4技术篇中登台担当演讲的代表人。
小岛工作室制作部程序组技术总监高部邦
两位说道,虽然根据场景的不同情况不同,但一个场景平均的背景POLYGON数为25万到35万的程度。草比较多的场景,光草的POLYGONG数就超过了10万。
在这些背景的基础上,加上角色和其他用于特效的渲染模型,估算POLYGON总数达到40万到60万。再加上用于生成阴影等不可见的素材的渲染用POLYGONG,GPU的负荷接近100万的POLYGON数的场景也是有的。
1个角色平均的POLYGON数大约在5000到10000之间。特别是像雷电,CAMBELL, OTACON等主要的角色POLYGON数达到1万的程度。
而且主人公SNAKE,在PS2版MGS系列最后一部作品MGS3中是大约4400个POLYGON,PS3版的MGS4达到了14000个POLYGON,大约增加到了3倍的模型数量。还有,SNAKE的模型在游戏,过场动画以及安装时的近景是同一套模型。
根据笔者的取材,在其他游戏开发工作室中,在PS3,XBOX360,WINDOWS-PC这些次世代的高配置的游戏平台上(以下简称次世代HD游戏机平台),认为把100万多边形作为GPU的一个描画负荷的做法是经常看到的。MGS4也大体接近这个数值。在角色方面,第3人称游戏的话一般POLYGON停留在数千个面左右的作品很多,但在MGS4中近景镜头非常的多,相比现在的HD游戏机平台的标准值在对应上还稍微多了一些。
PS3版MGS4的SNAKE为14000POLYGON
没有法线贴图的普通版MGS4的SNAKE
应用了法线贴图的MGS4的SNAKE
上面是MGS3的SNAKE,下面是MGS4的SNAKE
MGS4的SNAKE的线框图
MGS4 SNAKE最终渲染效果
MGS4中的POLYGON数很多,模型内设置的骨骼数也很多。MGS4中主要角色的骨骼数包括脸,手指在内一共115根骨骼。脸部36根,手指32根,身体47根。脸部为了对应近景的演出,加入了MGS3中没有的舌头,口腔等骨骼。
身体中的47根骨骼中,用动作捕捉的动画数据来驱动的为21根。意外的是,用动画关键帧来驱动的骨骼数比PS2的MGS3的要少。MGS4中实现了使用较少的骨骼来表现高质量的动画的技术。剩下的26根骨骼(47-21),是针对手肘,膝盖,手腕,脚那种在蒙皮时容易产生破绽的部分插入辅助骨骼,从动作捕捉数据中,在运行时算数地进行驱动的骨骼。
前出のスネークのボーンを可視化したショット
脸部的骨骼结构
骨骼数了解了后我们关心的就是动作的数量(动画数)了,用主人公SNAKE来做比较,MGS3中的SNAKE动作数为1200个,MGS4中SNAKE的动作数为1700个。这里不仅仅是MGS4,就MGS3的SNAKE的动作数就惊人的多。由于MGS中的角色都是演技派的,大量的动作数据应该说是MGS系列中角色的一个尤其突出的一点了。
一个场景平均的贴图量大约为160M,这里指每个场景的高光贴图,法线贴图,DECAL贴图等主要贴图的总量,不包括用于生成阴影的SHADOWMAP,用于生成水面的WRECK BUFFER等图像引擎方面占用的贴图内存容量的数值。
根据图形引擎的设计上的具体原因,用于生成动态阴影的SHADOWMAP相关的显存方面,和水面相关的,以及其他用于PreRender的,用于正常渲染的动态生成的贴图素材等一部分贴图放在主内存中。一部分贴图放在主内存中的设计在次世代HD游戏机平台的游戏引擎中是很常见的。
从角色单位来看,主要角色的贴图平均每个5M,杂鱼角色贴图每个3.5M左右(DXT1,DXT5压缩后的数值)。贴图大小为脸部512X512PIXEL,身体1024X1024PIXEL。这个数值并不浪费,正是因为通过SHADER表现出的更多彩的实时阴影和贴图的相乘效果,使得MGS4的视觉效果看上去丰富。
显示FRAME的渲染分辨率固定为1024X768像素。这个对应到显示器的输出分辨率,会放缩到16:9的比率进行显示。并不是1280X720的原因,是为了跟重视纵向分辨率的原因。
根据场景复杂程度设计了上下可变的帧刷新速率,通过调整,游戏中的FRAME RATE基本上维持在平均30FPS的水平。还有,系统的本体设计的是为了对应60fps的设计,因为游戏逻辑和渲染基本上是同步的设计,所以即使任何一个方面有超负荷的情况发生的话,都不会发生不同步。另外高部说到MGS4在过场动画中因为采用了实时渲染,比起严格遵守30FPS的要求,我们更重视视觉上的爽快感。
MGS4的SNAKE骨骼结构,每根手指都设置了骨骼
辅助骨骼OFF的截图。手臂弯曲时手肘朝向不自然
辅助骨骼ON的截图。手臂弯曲时手肘朝向很自然
■ HDR渲染采用整数BUFFER的实现方式
不采用HDR渲染,较暗的场景中阴影完全糊了
采用HDR渲染,较暗场景中的阴影清晰可见,炫目的室外场景显得很明显。实际上眼睛看到的也是这样的感觉,采用HDR渲染的就更自然
作为次世代的渲染优点,无论如何都不能缺少的就是HDR(HDR Dynamic Range)渲染。
MGS系列的情况,无论从技术上说怎么样,其招牌是一款动作潜入作为主题的游戏,因此无论如何我们都希望能正确地表现暗处的效果,本作MGS4中活动范围已经扩展到了白天,在全黑的场景和全亮的场景间穿行是不可避免的。暗处要标志性无论技术上怎么样,作为型分插入辅助骨骼,在要表现这样的真实光影效果,HDR渲染的导入就是不可缺的。
MGS4中的HDR渲染的实现,在开发初期经过了各种各样的实验,最终才确定下来了制作式样。针对最新PC的GPU,其浮点BUFFER的功能和性能都很完备,所谓HDR渲染就等于使用浮点BUFFER的说法是成立的,但PS3的GPU“RSX”是基于距现在2个世代前的NVIDIA的GeForce 7800 GTX,针对浮点数BUFFER的机能性是很低的,理论上是不能实现浮点BUFFER的。具体的理由为以下。
第一,RSX(相当于GeForce7800 GTX),对于16Bit浮点数Buffer,有无法使用MultiSampleAntiAnliasing(MSAA)的限制。这会造成画面上有锯齿,作为重视最终画面美感的MGS4来说是无法采用这种方法的。
第二点,担心Frame rate不足。ARGB的FP16格式的Buffer大小是64Bit,在高分辨率渲染下,对于RSX的128Bit的带宽来说稍有难度。还有,GeForce6000/7000结构对FP16 Buffer的半透明合成处理是很慢的,RSX也继承了这个特性,这部分也是很大的瓶颈。
结果,我们还是采用ARGB全8Bit整数型,通常的8888的32Bit整数型Buffer来进行渲染。Int32Buffer是无法做HDR渲染的,所以要做些工作来存储HDR格式。关于这点,每个公司都有自己的做法,但趋势是通过引入固定小数点的概念,把HDR信息压缩到2倍的亮度范围,用INT32的Buffer来表现。参照真女神转生2的3D图形讲座。
针对这点,MGS4采用把亮度的倒数存储到ALPHA中的方法。具体的是,取像素的RGB 3个通道亮度值的最大值作为该像素的亮度,把这个最大亮度值的倒数在256色(8BIT)中表现出来。该最大亮度的倒数存储在ALPHA中,RGB存储的是用该最大亮度除过的数值。当然,计算是在整数型中进行的,所以肯定会产生误差。主要思路就是把HDR值进行不可逆的ENCODE来压缩到8Bit精度。
MGS4采用的最大亮度倒数的存储方式的HDR渲染。以0.25为基准亮度值来实现的改版
在该渲染管线下,在读取生成的ENCODEBUFFER中数值时,需要进行相反地DECODE操作。就是把RGB中取出的值和ALPHA中取出的值(最大亮度的倒数)进行合成来求得相应的数值。
这种方法,存储在ALPHA中的数值(RGB的最大亮度的倒数)越接近1.0(0-255),表现精度越高。(ALPHA中存储的亮度数值在1.0一下的话等价于通常的LDR渲染。
高部说到,暗场景较多的MGS4中最大亮度在1.0以下的场景很多。直接使用这个最大亮度倒数的存储方式,在亮度1.0以下的暗场景中色分离很严重,明显是存储精度不足的原因,所以我们把亮度值以0.25为基准的来实现效果。
这个存储结构下的特性是,ALPHA中存储的值越接近0误差越大,越接近1精度越高。因此和MGS4的场景特性结合,把存储在ALPHA中的亮度数值从最大1.0缩小到最大0.25。根据高部所说的,采用这种方式,亮度值能表现到从0-50程度的实用水准。
可视化HDR ENCODE BUFFER
TONE MAP后的COLOR BUFFER
因为采用了使用32Bit Buffer的HDR ENCODE 渲染方法,就能够实现在FP16下不能实现的MSAA,此外,因为存储带宽的消耗能控制在和通常的32Bit Buffer渲染相同的情况,所以performance方面是有优势的。但是也是有代价的。
在读写该Buffer时要进行ENCODE(写入)和DECODE(读出),处理上的计算负荷再轻,但仍然不是无消耗的。伴随多次的Buffer读写进行的处理也造成了负荷。本来Buffer是必须DECODE,ENCODE的,而且通过Bilinear filter采样后不ENCODE,DECODE直接处理的话,伴随着的画面品质的降低是很明显的事,所以只限在高负荷的处理时,省略对Buffer进行读写时进行的DECODE,ENCODEC处理。具体的讲,在之后讨论的景深模拟等情况下会采用这种省略方法。只是副作用是有比较大的误差的,模糊部分的HDR信息丢失了。这个从游戏方面来说,判断下来应该优先考虑PERFORMANCE。
保留HDR,来进行景深模拟的情况。自发光呈现高亮度,按照光圈的形状来进行模糊
无视HDR来进行景深模拟。自发光的高亮度信息丢失了并进行了模糊
■Blendbuffer rendering的最优化想法
采用使用32Bit buffer 的HDR Encode rending手法,虽然能达到同时表现HDR和采用MSAA的目的,但对于这个RGBA的buffer来说无法实现直接的半透明描画处理。Pixcel shader的负担也很高,因此,[MGS4]采用了关于半透明的描画,使用其他buffer来进行的独特手法。
BLEND BUFFER的读写方式
这个方法在[MGS4]团队内部被称作是Blend Buffer Rendering技术。首先,使用前面描述的方法把不透明的画面内容用HDR Encode Rendering的方式Render到HDR Encode Buffer上(RGBE).然后,把半透明的内容按照场景深度由远至近Render到其他Buffer上(Blend buffer).
这个Blend Buffer上的半透明的内容的描画使用Fake HDR(把亮度控制在0.0-2.0的范围内)来进行。这样就回避了前面所述的Decode/Encode处理来进行Render,降低了负荷。这是期望的最优化效果的其中之一。
使用[MGS4]的Blend buffer方法来进行Blending的方法是,先限定alpha blend和加算 blend两种方法,然后先让blendbuffer初始化(R=G=B=0,α=1.0).向blend buffer写入时,使用图中表示的计算方式来进行。相比较HDR Encode rendering方法来讲是比较简单的。
HDR ENCODE BUFFER和BLEND BUFFER合成时的计算公式
具体做法是把配置了alpha值的RGB值写入,alpha值上写入后期和HDR buffer合成时用到的blend数值。对于RGB的计算是普通定义的alpha blend,add blend,在此不做说明。
比较特别的是alpha上的内容。Alpha blend是在blend buffer上的写入(1 – src_alpha),加算blend的情况是只针对RGB blend处理后就完成了,blendbuffer的alpha值不做变化。
最后,把先前Render的Encoded HDR格式的不透明内容和这个Blend buffer的半透明内容合成。具体做法是,decode HDR的不透明内容,调整到和亮度在0.0-2.0范围的fake hdr的透明内容在相同的亮度基准,在shader中进行blend合成,因为Blend buffer的亮度范围固定在0.0-2.0之间,有超过这个亮度的半透明物体的情况下会被clip,无法显示出正确的结果。相反,在比较暗的场景中也有可能发生色阶不足的情况。但是,用blend处理的方法合成的色阶,这样的问题不是很明显,所以[MGS4]把 blend buffer的亮度scale这样固定下来的。
高部说到BLEND BUFFER的亮度范围固定在0.0-2.0之间,亮度超过这个范围的半透明的情况会被clip到0-2之间,从而无法得到正确的结果,相反在暗的场景里可能会有色阶不足的现象发生。但是,在混合处理时被合成色阶看上去色阶不足的问题并不是很明显,所以在MGS4中我们固定下BLEND BUFFER的亮度范围值来实现效果。
理想的情况下,亮度范围固定到0.0-2.0范围的blend buffer的内容,必须和HDR buffer的内容的亮度范围一致,但是[MGS4]省略了这个处理。假如,真的要去仔细作的话,要把前一桢的HDR Encode buffer的内容的平均灰度中求出亮度scale,考虑到这个亮度scale来进行合成。
不透明内容的HDR Encode Rendering是可以同时使用MSAA的Rendering,,而因为半透明BLENDBUFFER无法使用MSAA,这部分的表现有可能能解决。这是第二个期待的最优化效果。
对于没有针对BLEND BUFFER的MSAA这件事,意味着是无法回避锯齿问题的. BLEND BUFFER的内容是半透明的,能看见后面透过的部分,锯齿几乎不是很明显。反过来说半透明内容的MSAA的效果本身就不明显,所以没有MSAA的问题就不是很大。这方面的方法就是所谓在仔细考虑了在消耗机能和得到效果上的平衡后,重视3D游戏最终表现的图像效果的一种平衡全局的实用方法。
HDR ENCODE BUFFER的内容
非HDR的BLEND BUFFER的内容
完成版画面(只是TONE MAPPING前的效果)
对于高负荷,大范围的特效,我们引入了缩小BLEND BUFFER的尺寸的概念。这也是MGS4的HDR手法的特点
MGS4中,BLEND BUFFER和对应的Z BUFFER缩小到1/4, 半透明的效果被画到了这个缩小版的BLEND BUFFER上。分辨率缩小到1/4,负担也减少到1/4. 并且和HDR ENCODE BUFFER的合成是把缩小版的BLEND BUFFER bilinear扩大了4倍后进行的。
写入缩小版的BLEND BUFFER中的特效,利用深度值进行前后判定的Z BUFFER也是以缩小版的Z BUFFER来进行的,所以在和FULL 分辨率的HDR ENCODE BUFFER进行合成时,前后关系出错,虽然会有特效被错误地合成到BUFFER中去的弊害,但因为本来也就是半透明的物体,出错的效果也几乎很不明显。
MGS4中,远处的特效描画面积很小的情况很多,作为不容易造成高负荷,也能有更精细的表现,针对离视点很远的半透明特效,会画到前面所述的FULL 分辨率的BLEND BUFFER上,而离视点很近的半透明特效则会选择性地描画到缩小版的BLEND BUFFER上。也就是采用所谓的BLEND BUFFER LOD 的实现方法。
HDR不透明BUFFER(TONE MAPPING前)
全分辨率版的BLEND BUFFER
缩小版BLEND BUFFER
完成版画面(TONE MAPPING前)
所谓缩小版BUFFER,本连载中在 LOST PLANET篇幅中有过一些介绍,在LOST PLANET中,在降低了分辨率的缩小版SCENE TEXTURE上描画半透明的特效,然后把这个BUFFER和全分辨率的SCENE BUFFER进行合成。使用这种方法的话,透过半透明物体之后的场景的分辨率会有下降的弊害。而使用MGS4的方法的话,和最终的全分辨率的场景进行混合则没有这个问题。这也是采用MGS4的方法后得到的好处
全屏幕特效,在整个画面中出现的沙尘,吹雪的表现的话,会采用描画分辨率为1/16的低分辨率的 FOG EFFECT专用的缩小版BLEND BUFFER来进行大量的描画,目的是大幅度降低半透明的描画的负荷。
FOG EFFECT的描画完成以后,将该超缩小版的BLEND BUFFER进行扩大,通过比较SCEND的深度值和FOG EFFECT BUFFER的深度值(由于扩大,分辨率会大幅度打折扣),调整色彩饱和度,亮度,进行合成。由描画中顺序产生的半透明透过肯定会产生很多矛盾的地方,但原本FOG EFFECT自身就是很柔和,大场景的效果,问题不会很明显,我们可以无视掉这些瑕疵。
FOG EFFECT的例子(沙尘)
FOG EFFECT的例子(吹雪)
フォグエフェクトの例「砂埃」のムービー