注明:本文虽然讲述的是使用UE4移动渲染器开发手游,但在如何做渲染和优化等方面的内容很值得我们移动VR游戏开发者借鉴,希望本文能帮到大家。

随着移动设备性能的不断提高,高品质手游的画面表现力也越来越强,甚至不少人认为3A画质将成为未来手游的标配。那么如何来制作和渲染高画质的移动端游戏?UE4移动端开发负责人Jack Porter出席Unreal Open Day活动时,详细介绍了UE4移动渲染的多种方式,如何做移动渲染的九大步骤,包括光照和阴影组合的处理与使用,以及关于UE4移动端针对游戏包体大小、编辑操作等各方面新功能的改进。

除此之外,Jack Porter还介绍了韩国网石开发的《天堂2:重生》手游,在UE4引擎使用上的一些内容。

大家好,我是Jack Porter ,UE4移动端开发负责人。自1998年起便加入Epic Games 制作游戏,还参与制作了最早的《Unreal Tournament》和《Gears of War》系列。今天会着重分享一下UE4移动渲染器的功能、一些使用UE4开发的游戏,以及移动端渲染的特点。

除此之外,今天我会分享一些细节,包括在手机上采用OpenGL ES3.1、Vulkan和Metal实现高端画质,如果你是开发手游的,这肯定会有很大帮助。

接下来,我们看一下高端画质的手游市场。首先,3A级手游画质已经接近主机游戏的品质;其次,目前在手机上已经可以很好的运行开放世界的MMO游戏。值得注意的是,有韩国网石研发的《天堂2:重生》(以下简称:天堂2)在2017年2月份成为全球收入最高的手游。

天堂2手游实操案例

这是《天堂2》手游的一些截图,从图中不难看出该手游已经非常像一款标准的 MMO端游,明显已经提升了大家对移动设备上MMO游戏画面品质的预期。

我相信很多人都想复制这样的成功,现在我们已经完全可以在移动设备上做到这样高品质的效果了。值得一提的是,这款游戏并没使用什么黑科技,就是使用了UE4自带的所有工具。测试和制作都是在PC平台,他们的无缝大世界使用了我们的Landscape工具。通过Level Streaming使得你可以在无缝大世界里穿梭。

在UI方面,他们使用引擎自带的UMG编辑器,大家可以看这张图的UI,都是用UMG编辑器做的。在都设备适配方面,《天堂2》使用了Device Profiles工具 ,最低可以支持iPhone5和Galaxy S4这样的设备。

解读UE4多种移动渲染器

接下来介绍一下移动端的渲染器,看看它和桌面渲染器、延迟渲染器以及VR的前向渲染器有什么区别。大家知道UE4现在支持三种不同的渲染器模式,最普通的是延迟渲染器,这个渲染器在PC包括编辑器模式下以及主机模式下都是默认使用的,对应的feature levels我们叫SM4和SM5。

第二种是针对VR做的前向渲染器,这个渲染器的feature和我们前面的延迟渲染器基本是一致的,除了少了一些个别的效果,比如说屏幕空间特效、空间环境闭塞(SSAO)、屏幕反射(SSR)或者Contact shader 等。

移动渲染器虽然也是一个前向渲染器,但是它是一个简化的渲染器,主要去掉了在光照和投影方卖弄的功能,其对应的feature levels有ES2和ES3.1。

Feature Levels其实是指在材质编译器里中可以做选择不同级别的feature ,不同的feature level可以影响你在材质编译器里面使用着色器 的功能。Feature Levels同时也决定了刚才所说的哪种渲染器会被使用。

在移动端Feature Level有ES2和ES3.1,不完全等于OpenGL的 ES2和ES3.1,只要你的硬件支持,Feature Levels ES2的设备也可以运行OpenGL ES3.1。其中ES2是我们移动端最稳定最常用的一个Feature Level,正如此前所说,如果硬件支持,ES3.1也可以使用。因为Feature Level开关选项可以使得美术制作师在制作材质的时候区分不同的feature下材质的功能和表现。在编译器里面有一个预览渲染等级的选项,可以针对不同的Feature Level显示他们最后渲染的效果。

ES2是我们最常用、最稳定的Feature Level,比如说从最左边的Galaxy S3到Galaxy最新高端设备都是可以使用的,我们会自动做一些适配。我们在打包的时候把对应的shader都打包到版本里,会根据你的硬件自动来动态的编译要使用的shader。

因为这个Feature Level是跟你的ES2的Feature Level挂钩的,所以有一个限制是比如在低端设备只支持ES2的情况下,它的贴图采样只支持八个,这是一个很大的限制。高端设备可以支持更多的采样,但在低端设备上超过八个采样,该砍掉哪些,引擎是没有办法做出选择的,所以这是一个硬性条件。

新设备我们都应该支持,比如HDR要16位的浮点,所以要有64位的渲染目标,但是我们必须还要在ES2模式下支持一些非常老的设备,比如马力T600—700的设备,只支持32位的渲染目标。

OpenGL ES3.1对于移动端来说是比较高的Feature Level,初开始我们在iOS上支持Metal,现在我们加入安卓使用Vulkan的支持,如果你想在双平台上做高端效果可以使用Open GL ES3.1。因为在这个Feature Level下,有非常多的支持,包括Texture有16个,支持浮点渲染对象,顶点纹理贴图和对sRGB的支持,所以可以做出非常好的效果。

接下来是延迟渲染器。延迟渲染器最低支持的Feature Level是SM4,原来是针对DX 10的,但其实在iOS A8以上的设备,Metal也可以使用。曾经我们认为未来移动高端的走向就是可以使用延迟渲染器,但是最近我们觉得或许以后在高端移动设备上尝试使用现在我们新引入给VR用的前向渲染器。

Shader Model 5是常见的延迟渲染器,支持延迟渲染器和VR前向渲染器,针对的是D3D 11,包括支持主机平台和使用Metal的Marco 。

最后有一个比较奇怪的是,两年前,我们做一个高端效果的移动端DEMO,使用的是OpenGL ES3.1,加上安卓的扩展支持,当时是在Tegra K1平板上跑,也就是说在Tegra K1和X1的GPU上是可以跑延迟渲染器的,本来我们认为以后趋势是高端设备可以使用这样的延迟渲染器,现在我们发现这个路走不太通,因为这NVIDIA的两个移动GPU设计和它的桌面比较像,其他的都不是,所以最后我们可能是把Shader Model 5支持VR的前向渲染器移植到高端的移动端。

在编译器中打开这些比如支持OpenGL ES3.1和支持Vulkan 的话,其实有两个改动,一个是代码层级会包括对应的ES3.1和Vulkan的渲染器,也会同时生成和包括支持OPenGL ES3.1和Vulkan的shader,如果你们把这些都勾上发布到不同的设备上,其实引擎会自动帮你选择这个设备所支持的最好的Feature Level以及它支持的平台,当然你还是可以在Device Profile里面去覆盖你所写的设置,比如你可以在一个好的设备故意用Feature Level比较低的设置。

快速介绍一下Vulkan。Vulkan是下一代的中心API,现在已经支持安卓,在安卓7系统已经默认带有Vulkan的驱动。

Vulkan提供了更底层、更轻度的API,有了PSO的概念,以前你要绘制一个东西时,比如在OpenGL里,你先要设置shader、顶点数据、Texture等一大堆数据,都要占用CPU内存,现在只要在PSO对象生成完以后,只要设置它的一些属性,接下来把它传给绘制调用,这样一次就能绘制出来。

Vulkan也更好的支持了现在移动端的GPU硬件设计。

这是去年我们跟三星合作的第一个支持Vulkan的Demo——《ProtoStar》,这是第一个在安卓设备上可以跑ES3.1的 Demo。

接下来介绍一下我们的Color Buffer。

在HDR模式下我们会用到一个16位浮点的Scene color。在延迟渲染器下面,我们会把所有东西装进Gbuffer里,但是在移动端前向渲染器里面,我们直接把最终的颜色绘制到16位的浮点渲染目标中,因为这是16位的,所以你可以存高动态范围的颜色。大家可以看到右上角图片是高动态范围的Scene Color输出的一张图,保留了很多颜色范围的细节,包括云这里的高亮的白色以及阴影下比较暗的黑色。

当然移动设备的显示屏幕并不支持高动态范围的输出,所以我们用色调映射做后处理,,映射回一个32位的Backbuffer(后背缓冲区)。

大家可以看到下面这张图是我们最终映射完之后的Backbuffer,比较暗的地方也能看得比较清晰了,亮的地方也没有之前那么亮了。

刚才有提到,在HDR模式下我们需要16位浮点、64位的渲染目标,,但我们仍然希望一些不支持16位浮点,只支持32位的设备能够跑HDR,我们在支持这些扩展的设备上,比如Galaxy S6/Note 4shouji ,我们用RGB和指数编码来达到HDR的效果。

还有一个直接渲染模式,就是LDR模式。在这个模式下我们直接把颜色写回到最终的Backbuffer,这是最快、最有效的效率。然而,这个模式下的Backbuffer是在EGR里面申请的,引擎没有办法直接操作和访问的,导致了很多效果在这个模式下是没有办法支持的,比如说一些后期处理的效果,延迟的贴花和阴影调节等。

这个模式我们主要用来做移动VR。大家知道它对性能要求比较高,需要跑到60帧。这里我们还在做一些进一步的改进,因为其实在VR模式下,Backbuffer是最后会给包括Gear VR、Daydream驱动做支持的,所以我们觉得应该还是有方式来加上这些现在不支持的效果的。

移动渲染九大步骤

接下来我会详细讲解一下这完整的一帧在移动渲染器伤势如何渲染出右边这张图的效果的。

第一步,可见性。我们会用视锥裁剪、距离裁减和预计算的可见性剔除不可见的物体,关联视图、找出所有可见网格元素、收集动态网格元素、更新均匀缓冲区域。

第二步,我们会做GPU Particle(微粒)的一些模拟。在做这些模拟的时候,我们会输出两张渲染对象,一张是用来存放微粒的位置,一张用来存速度。每一帧模拟的时候,我们会从这两张贴图里读取前一帧数据,然后在Particle shader里做一些模拟计算,算出这一帧的数据再写回。这个是只在Feature Level 支持OpenGL ES3.1的情况下才会去做GPU微粒模拟,当然如果你用了Feature Level ES2,硬件支持ES3.1的花,也是可以去做GPU微粒模拟。

第三步,渲染Shadow Map。设置深度缓冲,取得需要shadow的物体,一般Shadow Map渲染都是从光源的位置来渲染,然后存它的深度信息,给后面的Base pass或Modulated shadow projection使用。

第四步,Base Pass。Base Pass里绘制整个场景,包括计算光照和投影。在这种情况下Shader组合情况还是比较多,可能是无光模式,可能是动态加静态光照,可能是带距离的投影加上Shadow Map。在这种情况下shader排列组合会相当多,这也是最终导致你的APK包比较大的一个原因,包含了各种组合大量的shader,实际上大部分的组后可能是没有用到的。

好在4.14以上的版本我们已经在编写里可以有一些选项排除到掉你肯定不会用的组合来减少shader组合爆炸生成大量的Shader。动态的物体在场景里面移动可能受到光照的结果计算都不一样,所以我们每帧都会计算,但是对于静态的物体我们只会在第一次加到场景计算一次。

现在拥有所有Base Pass要用的Shader,就可以把所有的场景绘制出来。在经过Base Pass以后,大家可以看到整个场景从什么都没有就已经有基本上现在这个样子了,在这里我们已经把各种动态和静态光照投影和反射绘制完。

接下来是绘制顺序的排序问题,这跟设备是有关系的。比如说对于ImgTec默认选项的GPU,有一个功能叫“消除隐藏面”,所以不需要重新排序,被遮蔽的像素是不会重复计算的。

对于其他的安卓设备来说,我们一般都会从近到远排完序来绘制,这样利用深度缓存就可以最大限度减少透支。在这种排序的情况下,我们有两种可选的方式,一种是直接从近到远的排序;还有一种模式是把材质一样的东西并到一起,能减少状态切换,渲染现成的CPU特效。我们默认是使用前后排序的,如果你用了很多不一样的材质导致你的状态切换特别多,开销很高,你可以用我们下面列出的命令来强制它使用先合并再排序的方式,对于高通的GPU尤其有效。

第五步,延迟贴花。因为没有Gbuffer,所以这里只有颜色信息,所以我们的延迟的贴花在移动端是不支持和光照计算的。

第六步,阴影调节,也是在延迟Pass里面计算的。因为在这个时候你只能访问前面整个计算完的颜色,所以它有一个很大的问题,就是不能好把动态的投影和静态的投影融合起来,所以在4.12以后的版本我们推荐大家使用静态的阴影加动态的CSM。

第七步,画半透明。因为因为半透不能写到深度,然后肯定要透支上去的。

第八步,后处理。在后处理上,我们可以完成一项DOF的效果,也可以自定义你的后处理的材质,最后我们会做色调映射,把它映射到低动态的范围屏幕上的颜色。

第九步,HUD&UI。在前面的几步全部做完之后,我们就要在Backbuffer里直接绘制所有的Slate UI和Canvas,然后交换Backbuffer,最红绘制出来。

光照和投影组合使用

接下来讲一下关于光照和投影的组合。

第一个是全动态的光照。全动态光照有一些好处,比如开放世界的MMO游戏就用了这样一个全动态地光照设置,你不需要烘焙大量的光照贴图数据,所以你的包体大小和内存大小都是比较小的,你可以实时的改变所有的光照信息。

全动态光照的缺点是,高品质的投影本来都是静态,在这种情况下就没有了,所有的东西都会绘制到CSM。因为所有的东西都画到CSM里面,所以CSM的所有精度会不够,本身开销也比较高。

这个设置是最简单的定向方向光的设置,所有的东西都是烘焙完的,所以效率相当高,品质也相当的好。当然问题是因为它是静态烘焙完的,所以对于大型的MMO游戏可能包体、内存占用都比较大。

在最近的版本里我们现在加入了定向方向光和CSM shadows的组合,那就是说场景静态的东西都是烘焙好的,是Distance shadows,动态的是CSMshadow,它们能够很好的融合起来。在刚开始的时候,其实这些需要你要自己手动选择,比如哪些可以接受静态的CSM shadows,哪些是投出CSMshadow的,在新的4.14的版本以后这个设置就是自动的。

大家可以看到图上大的球是动态的CSM shadow,移上去的时候会跟静态已经烘焙好的shadow融合的非常好。

一些可能有的缺点,一个是你要投动态的CSMshadows会有额外的开销,因为你动态的对象很少,投的东西很少,开销也不会太高;另外一个限制是它会额外的占用你一张Texuture,所以只有八个情况会比较吃紧一些。就像刚才说的ES2只有八个,所以你用不了八个记得要关掉。

接下来我们是支持动态的点光源的,这是在Bass Pass 绘制的,所以没有额外开销,当然缺点是它可能会导致你的shader的组合数量变多。从4.15开始我们在protect setting里面的movable rendering里有一个排列组合,比如你的整个项目都没有用到动态点光源可以把组合勾掉,可以最大的减少最后生成的shader的数量量和包体的大小。

在4.13以后的版本我们支持了Lighting channels光照通道。那么你只要对某一个物体和光源设置了同样的光照通道,他们就会互相影响,不会影响剩余其他的场景。

图中左边是有一个绿色的点光源和一个白色的方向光,右边这张图我们把方向光和绿色点光源放到了一个Lighting channels里面,所以右面的图大家可以看到绿色的点光源只影响了正方体,没有影响其他的场景。移动端的Lighting channels限制是同时只有一个方向光可以影响每个物体。

在新版本中我们引入了影视化的色调编译器,对于那些希望把颜色调得像电影一样的美术来说,这是一个很好的效果。在4.15版本中,我们想使整个引擎的渲染变得更加物理真实,所以我们默认打开了Tonemapper Film,那带来的问题是这个在移动端虽然效果很好,但是跟用的比开销大不少,所以一般只会用在比较高端的移动设备上。

为了解决这个问题我们引入了一个分离的变量,专门来控制Mobile的Tonemapperfilm,在PC编译器模式下你是打开Tonemapperfilm,在移动端你可以把它设置成关闭。

在最近的4.13以后的版本里加入了自定义的后处理材质的支持,设计师可以自己定义最后的后处理流程里的一些效果。

与自定义材质配合,还有一个Custom Depth。在你选中的情况下,会额外的输出一张depth buffer,来绘制你刚才Custom Depth里面的一些效果。有了这个功能就可以把采样独立特别选中的设置对象再去提高到Custom Post  Process里面把它作一些使用,比如高亮勾边效果等。

在4.15版本里我们还加入了Custom Stencil,伴随Custom Depth,我们还会对每一个物体存一个独立的Stencil的值。比较典型的运用就是敌人和友方我们可以去画不同的勾边。当然由于移动GPU的限制,所以我们渲染出了一张额外的depth用来存stencil。

除了渲染呢,我们还做了一些其他的针对移动设备的一些改进。

第一种,下载包的设置。有一种设置是你可能希望初始包是最小的,仅包含初始的逻辑,当你第一次从Appstore/Google Play商店下载完打开应用的时候,会检测,有进度条UI,再去一些服务器端抓取实际的数据包。这个好处是你可以强制用户每次打开的时候强制检查和更新版本,而不需要他去应用商店里更新应用。这设置其实相当复杂的,因为你需要设置哪些是在初始的APK包里,哪些做DLC,哪些是要做patching的,自己要做很复杂的管理。

因为这个原因,我们做了这样一个向导的窗口,我们会问一些问题,让你设置一些资源在哪里之类的,会自动生成初始包和接下来下载的DLC的数据包。打包数据都有了以后,接下来到你打开应用的时候我们有功能可以检查你SD卡剩余空间是不是足够,你是不是连着WIFI等。基于这些需求我们把这些功能都包裹在了一个叫Mobile patch Utilities的BP库里面,大家可以使用它,显示出提示用户下载这些内容和下载提示框。

刚刚那种情况很多时候都已经适用了,但是在国内我们知道有些渠道厂商可能希望是一个大包,因为二次下载肯定会有流失。大家可以看到右面的图,《我守护的一切》在国内上线的APK包的情况,其实是沿用了我们以前的方式,是一个小包加下载内容的,一个原因是以前在超过两级的打包情况下,在某些安卓系统下可能会有问题,因为一些原因是谷歌的API问题,虚拟映射会占VSS,VSS超过两个G有的时候就会崩掉,这个问题现在我们已经修复了,所以现在已经没有任何阻碍,你想分包,还是想把无论多大的内容打到一个APK包里都是可以实现的。

在4.16里面对移动端还做的其他的改进,一个比较重要的是减小了执行文件的大小,比如把没有使用的代码没有再编译进去,在一些模板函数的重入我们也提示编译器选项在link的时候去掉,通过一系列事情用来减小执行文件的大小。

关于减小包体大小,很多会在4.16版本发布时更新,与此同时我们还会在后面的版本中持续改进。

另外一个比较明显的改进是在UMG UI的效率上。像右边的手游的UI大家可以看到元素很丰富,其实是非常复杂的。Invalidation Pano的改进使得这些计量大量的减少了折扣,我们对运行时的权限管理做了更多的改进,不会再应用刚打开的时候就弹提示框告诉你要使用什么功能,在你具体第一次使用的时候才会提示,如果你禁止下次再使用它会重新的提示。

还有一个4.16版本会加的新功能是材质编辑器里面有一个新的材质节点叫Vertex  Winterpolator。本身移动端的Vertex shader精度是全精度,Pixel的精度是半精度,所以有时候你会觉得精度不太够,一个技巧是通过Custom UV把数据传出去,左边是比较复杂的,现在这个节点就是为了利用UV直接把全精度数据传给Pixel Shader,开销会比较高一点,我们推荐使用这样的方式。

还有一些正在做改进的功能,下一个版本还不会上线。一个是改善项目迭代的时间,比如你只改了一点点内容或者改的一点代码的时候,我们希望用最短的时间重新迭代发布到社会上。

我们还做了一些改进,比如说在编辑器里预览移动端效果的改进,还有我们希望在PC端直接打包发布利用远程的系统来编译和发布到iOS的功能,现在其实也可以做,但是在设置方面有很多问题,会比较麻烦。

谢谢大家,刚刚是一些对我们移动端功能的总结,大家有什么问题?因为我就是做移动端开发的,所以特别希望知道大家在移动端有什么需求,大家可以台下找我。