[转载] 翻译 西川善司著针对3D游戏爱好者的”METAL GEAR SOLID 4”图形讲座(上)
http://www.cnblogs.com/arai/articles/1701543.html
西川善司著针对3D游戏爱好者的”METAL GEAR SOLID 4”图形讲座
揭秘开发人员的最优化成果,PS3最高端图形开发的秘密(上) 翻译:胡文杰
10月24日收录
会场: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采用的最大亮度倒数的存储方式的HDR渲染。以0.25为基准亮度值来实现的改版 |
针对这点,MGS4采用把亮度的倒数存储到ALPHA中的方法。具体的是,取像素的RGB 3个通道亮度值的最大值作为该像素的亮度,把这个最大亮度值的倒数在256色(8BIT)中表现出来。该最大亮度的倒数存储在ALPHA中,RGB存储的是用该最大亮度除过的数值。当然,计算是在整数型中进行的,所以肯定会产生误差。主要思路就是把HDR值进行不可逆的ENCODE来压缩到8Bit精度。
在该渲染管线下,在读取生成的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的最优化想法
BLEND BUFFER的读写方式 |
采用使用32Bit buffer 的HDR Encode rending手法,虽然能达到同时表现HDR和采用MSAA的目的,但对于这个RGBA的buffer来说无法实现直接的半透明描画处理。Pixcel shader的负担也很高,因此,[MGS4]采用了关于半透明的描画,使用其他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到0-2之间,从而无法得到正确的结果,相反在暗的场景里可能会有色阶不足的现象发生。但是,在混合处理时被合成色阶看上去色阶不足的问题并不是很明显,所以在MGS4中我们固定下BLEND BUFFER的亮度范围值来实现效果。 |
因为Blend buffer的亮度范围固定在0.0-2.0之间,有超过这个亮度的半透明物体的情况下会被clip,无法显示出正确的结果。相反,在比较暗的场景中也有可能发生色阶不足的情况。但是,用blend处理的方法合成的色阶,这样的问题不是很明显,所以[MGS4]把 blend buffer的亮度scale这样固定下来的。
理想的情况下,亮度范围固定到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的例子(吹雪) |
フォグエフェクトの例「砂埃」のムービー |
■ 比起物理方面的正确性,跟重视电影效果的环境照明,由美工手动设定半球照明
VALVE的HALF LIFE2是作为第一个采用AMBIENT CUBE的作品 |
虽然现世代的3D游戏图形中几乎不怎么谈论到,但这两年,慢慢开始注重细节的画面引擎,这就是拥有特别环境光照的画面引擎。一直到PS1,PS2时代为止,所谓环境光就是根据场景设定一个适当的颜色来表示。也就是说针对动态的光照效果,没有一个彻底提升效果的设置参数。在画面表现力有大幅提升的现时代中作为吧角色融入到场景中的手法,或者说使角色有存在感的手法,就特别注重环境光的处理方法。MGS也可以说是一个很好的例子。
所谓环境光,不是从某个光源射出的直接光,而是根据相互反射等方式生成的二次光源(间接光)的总体,本来的话为了必须正确地得到光照效果,会进行辐射度计算,而现在简单地表示成在这个空间中存在的光。MGS4中,这个环境光的效果是用了消耗既低,又能得到较好效果的“半球光照的”方法。
现时代的3D游戏图形中人气很高的环境光是“AMBIENT CUBE” ,或者被称为辐射度VOLUME的手法。这个手法是预先进行场景辐射度的计算,在场景中相间隔适当的距离来设定带有方向的环境光,在实际的光照时会查找该区域的AMBIENT CUBE,来设定环境光的技法。
高部说到,我们在开发初期采用的是AMBIENT CUBE的实现方式。但是,美术组对结果并不满意,从物理上来说是肯定是正确的灯光效果,但角色太融入整个环境了,我们希望使角色能稍微显得突出并有存在感。这样的话,必定需要美工手工调整AMBIENT CUBE的数值,但手工指定太费工夫,所以我们采用半球照明的方法 |
|
半球照明的演示图 |
这样的制作方法的判定在电影制作中的打光阶段也是经常被使用到的。为了让演员看上去更漂亮,会避免场景中只有从窗直射进来的光,那样鼻子在脸上的影子过于强烈,效果不令人满意,这时就会从脸的正面方向打一个较淡的灯光。MGS4中也是虽然有基本的基于物理表现的效果,但也会根据美工的需求来设定有电影化效果的环境光,就是之前所说的采用简单的半球光照。
半球照明在本连载中的篇中有详细的介绍,具体可以参照该文章,在这里简单解释说明的话就是把环境光由2个方向的光组成。一般简化成地面上的环境光和天空光2部分组成的模型,在MGS4中我们将其扩展为任意2个方向的光的概念。
在AMBIENT CUBE方法中,会把场景按一定距离来划分,自动组成若干个环境光。MGS4中,美工可以在每个场景中的任意方向,任意影响范围里,(有BOUNDING BOX指定)来设定环境光。即,美工会在场景中(包括指定影响范围),设置从2个方向照射的假象的照明器具 。还有,因为影响范围是设计成能够由层级指定的,例如越接近设定的的半球灯光,就能切换影响的半球灯光这样的设计结构。
开发中使用到的半球照明的设定工具的画面。 |
■ 使用分离PRELIGHTING模拟辐射度表现(HALFLIFE2中使用的NORMAL RADIOSITY MAPPING)
分离PRELIGHTING的概念图 |
为了让角色的表现更令人印象深刻,我们使用了半球照明,通过放置半球环境灯光,就能够来表现在动态角色身上的模拟辐射度光照的效果(相互反射,间接光照等表现效果),而在MGS4中,和动态角色的处理方法不同的是,对于背景我们使用复杂的环境光表现手法。这就是在开发团队中被称为分离PRELIGHTING的技术。
具体做法是,在场景中美工设定分离PRELIGHTING专用的光源,把光源计算的光照效果预先烘培到背景的POLYGON模型的各个顶点的附带属性上。简单来讲,相当于顶点单位的LIGHT MAP。光照结果的烘培,该方法的特点是在相互垂直的3个方向的基准向量上进行的。
这3个方向的光照结果会烘培到构成背景的模型的每个顶点中,包括用于背景模型的法线贴图等阴影处理方法也可以利用这3个方向的光照的结果。
这样处理,即使在较暗的环境中,在阴影中向来缺乏效果的法线贴图也能产生非常丰富的阴影细节。这就是这种技术的实现带来的最大的恩惠。而且,美工是在设计场景时设置这些灯光,而且这些分离PRELIGHTING用的光源数没有限制,通过仔细设置光源的放置方法和光源的强度,就能实现有辐射度表现的背景效果。
只有分离PRELIGHTING |
同一个场景的完成FRAME |
在开发中使用分离PRELIGHTING的设定工具的画面 |
还有,光的分布分辨率本身也是在顶点单位上的关系 ,效果比LIGHTMAP要低很多,但在这方面,贴图的显存消耗完全节省下来了,这就是其优势。还有,背景多边形的各个顶点上烘培光照效果的工程不是在开发阶段完成的,而是在游戏启动之后,在PS3开发机运行时进行的。因为这个实现方案,我们就可以动态地针对场景的变化来对应烘培光照效果,这也是其一大优势。
例如,一旦在街灯中放置灯,就会咋这个街灯的光的影响范围上新设置一个用于分离PRELIGHTING的光源,通过再次计算来更新分离PRELIGHTING的信息就可以了。这样做的话,街灯在点亮之后,就能得到实现动态光相互反射的辐射度效果。并且,当该街灯被破坏时,相反地会删除这个用于分离PRELIGHTING的光源并更新分离PRELIGHTING的信息,街灯也会相应表现出熄灭后的相互反射的辐射度效果。
烘培的光照计算结果因为是顶点单位的原因,表现精度低,并且如果顶点数据附带的信息很多的话,PERFORMANCE会很低的这些问题在PS3的RSX上对PERFORMANCE是严峻的考验。但在现阶段应该是比较现实的能够做到的,比较合情合理的用来模拟相互反射表现的一种实现方法。
分离PRELIGHTING对应动态场景。当击中电灯后,周围的环境光就消失了。这是通过删除消失后的分离PRELIGHTING的光源来实现的。 |
(C)2008 Konami Digital Entertainment