GameLook报道/2020年12月7日- 10日,由腾讯游戏学院举办的第四届腾讯游戏开发者大会(Tencent Game Developers Conference,简称TGDC)在线上举行。
TGDC自 2017年创办以来,一直坚持以开发者视角与需求为出发点,结合行业发展趋势,对大会内容进行不断升级和扩充,旨在为国内外游戏专业人士打造开放的交流分享平台,推动游戏行业良性发展、探索游戏更多可能。
在第二日(12月8日)的活动中,来自腾讯互动娱乐《天涯明月刀》手游引擎技术负责人刘冰啸在演讲当中,总结了在《天涯明月刀》手游的开发历程中,几项关键点的技术决策和开发的经历,包括技术测试和应用,以及这些先进技术是如何落地的,为我们揭开了《天涯明月刀》手游高品质背后的秘密。
以下是演讲实录:
刘冰啸:大家好,我是刘冰啸,我来自腾讯《天涯明月刀》手游项目组,目前在担任手游引擎的技术负责人。这次演讲将给大家带来《天涯明月刀》手游的开发历程,包括其中几项关键点的技术决策和开发的经历。
《天涯明月刀》手游是一款基于真实的物理渲染的国风MMORPG游戏,它延续了天刀端游的画面表现力,在手游平台性能受限的环境下,达到了这样的效果,甚至超越了端游的表现。这可不是简单的画面移植,背后的一切是怎么发生的呢?我作为天刀手游引擎技术负责人,将给大家带来背后的开发历程。
我们将要看一下天刀手游的先进技术,是如何在天刀里面落地的。
我们去考虑手游引擎开发的几个重要要素:首先就是画质,画质我们需要进行一些选择,是希望它突出远景,还是希望它突出近景;画面的表现上是优先于室内,还是优先于室外;整个画面效果是鲜艳,还是更加自然;在光与影之间是做取舍,是优先光线的表达,还是优先影子的效果。
第二是帧率,对于天刀手游这种,属于强交互的MMORPG的动作类游戏,我们需要一个高而且却稳定的帧率。通常在PC开发的时候,我们只需要顾虑到两个方面,先达成画质的效果表现之后,通过优化来不断地提高游戏的帧率;我们帧率达成一个目标点之后,再想办法引入更好的画质的表现。两者产生不停的迭代,来提升整体画面的效果和优化表现。
而对于手游来说,我们引入了第三个维度需要考虑的问题,那就是功耗。功耗对于手机而言,是非常重要的一个维度,它不仅会产生发热,而且还会影响到玩家游玩的单次时间。
在这三个维度上,对其中任何一个维度的增加,都会影响到其他另外两个维度的表达。
对于天刀手游的优化来说,我们开发引擎组采用了各种各样的技术栈,从而获取更好的优化效果。我们对多线程渲染引擎进行优化,把大部分可以并行的工作,比如动画、布料,都放到其他的线程中去运行。我们使用了ISPC来自动生成NeonSIMD的代码,这部分代码可以更好地提升CPU的执行效率。
同样在GPU和CPU的遮挡剔除中,我们使用了不同粒度的遮挡剔除算法,首先启用了Vulkan API ,然后通过Vulkan API来对GPU的内存 ,进行更好的粒度上的管理。我们还实现了GPU driven的渲染管线,用compute进行辅助优化各项其他的渲染技术。
在画面上,我们使用了PBR的材质,以及真实的物理单位的lighting,从而获得更好的、真实的 HDR的画面效果。
随着手游的每次测试,我们都会加入一个重要的优化或者功能。在第一次测试中,我们对Unity 进行了多线程的框架改动,把渲染线程和提交线程从主线程中剥离出来,因为在手游的开发环境里,一个主要线程的持续工作会带来手机芯片的功率提升,而它的功率提升则会带来更多的发热。
在第二测试中,我们引入了Vulkan API ,Vulkan API相对于GLES而言,有着更好的更轻量级的调用,经过测试,我们可以做到在提交线程上,获得30%的CPU的效率提升。因为Vulkan API是更加自由的开发方式,你可以在其中进行各种各样的优化,例如我们对一些比较重的 Vulkan API操作,例如Descriptor Set的绑定、layout的绑定,我们都可以采用一些Cache的方式来去做,这么灵活的Vulkan API,使得我们在做开发的时候可以获得更好的解法。
在第三测试中,我们引入了GPU Driven的技术,通过GPU Driven技术,我们可以把大部分CPU上的工作,转移到GPU上去运行。这不仅提升了GPU的效率,也减少了从GPU到CPU之间的 各种传递的带宽。我们将这项技术里面用在了游戏内部的地形、草和植被上,包括在家园里面也运用了这些效果。
在第三次测试里面,我们修改并提升了游戏整体的光照表达,引入了自动曝光,提升了Tonemapping的效果,解决了由于真实物理单位引入之后,在不同的光照环境下,lighting体现的一些细节颜色丢失的问题;我们重新对sky lighting进行了定义,使得整个场景的室外表现
更加丰富并且具有对比度。
时间有限,在这里我主要讲一下,在第三次测试中我们采用GPU Driven技术,来对渲染技术进行优化的一些要点。在开发的过程中,我们经历了多线程的优化,同时也发现了在做手机平台的一个优化的甜区。
其实手机的多核,要比在端游时代开发的时候,更早进入了多核时代,现在安卓手机很多都是四加四的多核架构,这有点像我们能够在上一代的主机平台上看到的形式,例如xbox360或者ps3 ,在这些架构下,都能够让开发者更多地使用这些辅助的计算单元,来提升你的计算效率。
对于引擎组来讲,我们采用了两个方向:第一个方向是尽可能地剥离主线程上的计算,通过dispatch到小核上、dispatch到其他线程上,来提升它的计算效率;第二个方向就是把计算转入GPU compute。
为什么说GPU compute如此重要呢?首先我认为它是现代渲染框架的一个基石,大家都了解除了GPU进行光栅化处理的部分之外,compute能够完成大量的GPU的渲染流程上的操作,包括计算光照、计算材质等等;另外一个值得注意的是,compute的渲染语言其实完全能和GPU的硬件对应起来,例如里面的Local Data Storage机制、ThreadGroup和Thread利用率的概念,这两个都能很好地在compute语言上表现出来。
第二点是因为使用compute能够发挥Vulkan更大的潜力。因为Vulkan本身可以对GPU的同步行为做出非常好的控制,而compute作为一个独立的单元,我们可以把compute计算,很好的和GPU的其他计算并行起来,例如compute可以和一个带宽优先的,比如shadow pass,进行并行;另外compute是一个单独的Queue,我们可以对比vs和ps的整套pipeline来说,它是一个非常简化的单元,是非常容易到处去摆放的。
第三点采用compute的话,可以给GPU Driven和Bindless打开更广阔的优化空间,甚至可以使用Async compute方式。来更进一步的并行compute和GPU的单元。
对于天刀手游来说,打开compute的关键突破点就是GPU Driven的地形系统。
我们来看一下使用compute作为GPU Driven的一些研究方向。在最近的几年里,GPU Driven其实是一个相对来说比较热门的研发方向,在SIGGRAPH 15上,育碧有一篇文章《GPU Driven的渲染管线》(GPU-Driven rendering pipelines),主要是讲《刺客信条:大革命》的开发。在2016年的GDC上,EA的寒霜引擎也提到了GPU Driven的pipeline,2018年FarCry5也实现了相关的功能,2019年育碧的机动车Fusion 也完成了相关的一些功能。但是在手机的领域上目前还没有相关技术,能够真正的在在线产品中体现出来。
那我们讲一下什么是GPU驱动的渲染管线?
首先GPU掌握实际的渲染控制。GPU掌握渲染控制可以提供更细致的渲染力度,例如在做渲染剔除的时候,CPU只能控制在object level,使用Object Bounding帮助下做剔除;在GPU这个层面上,我们可以做到更进一步的控制,可以在Mesh cluster级别上,通过切分Mesh来获得更好的力度控制。
它的另外一个好处是,它不需要GPU和CPU之间的数据来回传递,在理想情况下,GPU Driven甚至都可以使用一个Drawcall 来绘制完整个场景。当然了这个需要compute shader,以及indirect drawing相关API的支持。这些在Vulkan 1.0的情况下,我们是都可以拿到相关的支持的。
我们看一下,在天刀手游里面,GPU地形实施之后的结果。首先我们介绍一下CPU地形常用的算法,我们上一个版本里面的地形算法是CPU端的Geometry Clipmap算法,它采用的裁剪剔除方式是视锥的裁剪剔除方式,对比GPU Driven,它少了depth剔除,它计算LOD的方式是根据距离,而GPU Driven是可以根据距离以及地形块的复杂度来计算。
送入clipmap方式的顶点处,因为有两个pass,其中一个是要通过Virtual Texture来使用,在这种条件下,Geometry Clipmap算法处理后,渲染需要21万乘2的顶点数,而在GPU Driven情况下,因为获得了比较好的剔除效果,它只需要8万6的顶点数。
最后看一下GPU时间,在GPU Driven的情况下,我们在iPhone8P上,可以获得2.9毫秒的时间开销,这比通过CPU的方式下,节省了近四分之一的成本;而在CPU端获得收益更大,提交线程和渲染线程,每个都可以获得五毫秒以上的收益。
GPU Driven的流程主要包含GPU Driven和Virtual Texture两个算法 ,这两个算法的实现是有互相的交叉,出于简化我们只讲GPU Driven相关流程上的一些算法。
首先是深度的mips生成。这部分算法是在compute里面实现的,其次我们是在compute里实现GPU遮挡剔除,使用上一步制作的深度缓冲buffer。GPU的遮挡剔除主要是通过计算送入的patches的尺寸,看它处在哪一级的深度缓冲上,并对比这一级深度缓冲的深度和你的深度,来决定是否被depth剔除掉。通过这个流程我们可以获得可视的patches数目,根据可视的patches数目,通过compute来做indirect的Arguments的buffer,从而生成出来。
第四步就是把这些准备好的indirect buffer给绘制出来。这个就是整个地形使用GPU Driven的渲染流程。
在这里面有一个非常重要的优化,也在compute上是可以达成的,这个优化主要是利用compute里面的一个Thread shared memory的方式来做,它减少了对于CPU到GPU之间的多次的dispatch、减少了binding memory pingpong操作,在IMD的一篇文章里面也展示了这种优化更好的效果。它能应用的范围主要在于对你的buffer做filter,例如我们经常在渲染管线中提到的Bloom、高斯模糊、自动曝光等,这些对于区域进行filter的操作,都可以采用这些方法来获得优化。
我们看一下它怎么应用在天刀手游的地形体系里。首先我们会做第一次的dispatch,这个dispatch会产生16乘以16的线程组,每组128条线程,这128条线程读入深度,放入mips 里;第二步通过同步的方式,再把上一级的mips相邻的四个点取出来,合并选择最深的单位,写到第二级的mips里;然后依次类推 完成四级的写出。在第二个dispatch里,我们用同样的方法,dispatch一个线程组,128条线程,同样地把后面 32乘16的mips写入完成。
在GPU Driven的地形系统里面,我们仍然有另外一个机制的优化,这个机制是LOD体系。在Farcry的实现,主要采用的是CPU 四叉树的方式,来组织LOD的patches,根据相机的距离更新并选择CPU四叉树上的节点,送入GPU进行indirect buffer和GPU Culling。
而对于天刀手游来说,我们会把这些patch信息,先通过offline的方式bake出来,在每一个相机发生位置变化的时候,会去更新这些bake出来的信息,根据这些信息,再会去对改变的patch做过滤,生成新的indirect buffer。
我们看一下差异:首先第一步我们读到了所有的patches的属性;第二步我们根据视锥裁剪,获得视锥裁剪之后的结果;第三步我们再用HiZ产生的depth,产生一次depth裁剪。在完成这三步之后我们就可以生成Indirect Draw Arguments的buffer,然后 dispatch出去。
在我们完成GPU Driven的形成之后,引擎组会把这些所有的流程重新梳理一遍,再根据这些梳理出来的流程,去选择可以应用GPU Driven的其他渲染模块。其中比较重要的一个渲染模块,就是场景的植被管理。其实有经验的渲染程序可能直接会意识到这一点,其实草的geometry和地形的patch,或者是sector的管理是一个非常类似的概念,它们都有LOD,都有不同的geometry的表现。
我们绘制这些geometry LOD的时候最好的方法是通过Multi Draw Instanced Indirect的方案去做,另外一点是每种类型的草的Texture,它其实对应在地形上,更像是一个地形的Virtual Texture机制,也可以用bindless的方式去做绑定,可是在Vulkan 1.0的平台下,我们这两个API ,Multi Draw Instanced Indirect或者是bindless都没办法获得更好的支持。所以在天刀手游的实现里,我们只能采用将草的每种类型,完成一次GPU Driven的culling和Draw Indirect Buffer的生成的方式。
另外在天刀手游里,比较适合GPU Driven的场景是家园的渲染。家园的玩法在游戏里面,主要是可以让玩家尽可能多的定制我们整个家园的地形、地表、墙壁、物件、地板等,在这个层面上,其实它是需求非常多的geometry类型。
第二它的区域相对来说比较小,它只有128米乘128米的自定义空间,而在这种小的自定义空间情况下,遮挡剔除是必须要做的非常好的一种技术。
从这两点来看,GPU Driven是非常适合应用在家园渲染的情况,问题就在于,家园里面的这些物件,其实和草的类型一样,它都非常是依赖于Multi Draw Instanced Indirect和bindless这两种API的实现。对于天刀手游来说,我们只能退而求其次,我们利用地形步骤算出来的HiZ的buffer做遮挡剔除,送入一套做遮挡剔除buffer的内容,然后通过CPU从readback的方案,来获得这些buff er的遮挡剔除的结果,在CPU端组织尽量多的instance对象。即便采用这种方式,我们在家园渲染情况下也获得了比较好的渲染效率。
在完成了compute的基础机制上,我们在其上面也做了各种其他的尝试,其中有一条是完成了在ASTC和PVRTC的GPU实时压缩,这个也是通过GPU compute来实现的,这个功能可以用在角色的妆容系统上。在天刀手游里,整个角色的妆容系统是需要完成多个Feature的绘制,如果不能很好地去做baking到一张贴图上,在实时渲染的情况下,它会产生更多的开销。
在实时baking到贴图上,我们还希望它能够尽量去做压缩,来减少内存的使用。我们测试了一些compute compression的效果,在PSNR和效率上都能获得比较好的表现。
另外一个我们尝试的对于VirtualTexture的压缩。前面提到地形的VirtualTexture技术是需要更新大量的地形块数据,越多的地形块数据,才能使更新的频率变低。在天刀手游里,我们使用2048乘2048,三张不经压缩的材质,我们通过调整贴图的大小和贴图数量以及压缩方式,基本上能把大张贴图的时间控制在四毫秒以下,这个时间其实已经可以达到使用的效果。从远处来看,其实地表材质是很难观察到差异性,这是压缩前后的两张对比:
但是这种算法,我们对比了一下它的细节表现,仍然可以看到在开启压缩的情况下,它其实是有一些Blocking的瑕疵,但这样的瑕疵在我们游戏的画面品质情况下,是不能接受的,所以这种方案最终只能把它放弃。
另外一个compute应用的领域,我们尝试了Cluster deferred。Cluster deferred主要应用于家园室内场景,在家园的室内场景下,主要的因素是,首先它是一个封闭的空间,它仍然和之前家园的环境一样有大量动态的物体和光照效果。我们在这幅图上可以看到,家园物体里面有大概55盏灯,从左上角的一张蓝色的背景图来看,这个区域上最多的话,可以被8盏灯以上的照亮。
在这个技术方案实现之后,我们发现它仍然解决不了几个问题:第一个问题就是deferred本身的固有问题,它的带宽问题,它需要设计更好的GBuffer搁置,也需要去应用一些API ,例如subpass ,或者一些更好的pass combine的操作 ;第二是在于它材质的复杂度,一个deferred的材质和forward材质,在整个大世界的使用是很难做兼容融合的,这个也增大了shader的复杂度或者工作量,这种方向也许对未来是一个比较好的技术点,但是在现有的架构下,我认为它还是不够成熟,所以这套方案我们仍然是放弃了。
回到整个话题,我们从应用compute技术来看技术落地的情况。
我认为有几个决策是非常重要的:第一是需要有一个非常好的基础,这个基础就来源于我们在于从多线程开始,就意识到整个计算体系应该去往不同的compute方向,或者是往其他线程方向去使用,通过减少主线程的开销成本,来去提升整个游戏的性能效率。
我们让有比较好技术功底的同事完成了GPU Driven地形的突破。在这个基础之上,继续使用GPU Driven的技术。解决了一些场景植被和家园的渲染效率问题,我们compute还解决了像自动曝光等等相关的问题。
第三点则是在于技术落地和产品需求之间的要求,有很多产品技术可能是比较先进,但是它不能达到产品需求的质量品质,我们对于这种技术也只能忍痛割爱。
接下来是Q&A环节,我已经收到了一些小伙伴们,提过来的问题,我将会选择几个作答。
其中一个小伙伴提出性能优化时有什么技术难点,听说你们能以更低的规格实现更高标准,是怎么做到的?
问题非常有意义,其实我们在实现的过程中,没有特别去顾虑高规格和所谓的低规格,我们一般是设定一个标准,在这个标准之上再去找平衡。举个例子,对于我前面提到的光照或者是阴影的表达,我们认为阴影的表达是弱于光照效果的,所以我们仍然采用了比较传统的lightmap 来bake shadow的方式,我们并没有在大世界里面使用实时的阴影。所以我觉得这更像是一个平衡的问题,要基于你的游戏本身去承受的技术点,优先选择面,最终找到一个适合游戏要求的技术。
第二个问题是我想了解的是像这类的经典IP,从端游移植到手游,从引擎技术角度,如何更好地还原端游品质?
这个问题我觉得可能要从两方面来去回答,第一方面是说我们需要去还原端游的哪些特点,这个特点其实对于我们《天涯明月刀》而言,还是非常明显的:第一要更加注重远景的表现;第二我们要有更好的角色的表现。我们有些特定的技术点,的确也做到了比较好的还原,例如说云海效果。
基于以上的这些,我先要明确从端游还原到手游上的一些画面技术点,然后去制定它的关键的技术要素,例如说《天涯明月刀》手游仍然延续了端游的PBR的管线,但是我们其实是使用了比端游更好的,基于物理光照单位的lighting的方式,这样的话会使我们手游在暗光情况下的表现,甚至在某种程度上是优于端游的表现的。
我想这其实应该可以回答上面的一个问题了吧。以上就是我今天的所有的分享环节,谢谢大家的支持,也希望大家继续支持我们的游戏,同时有机会和大家更多的交流,谢谢大家!再见。
如若转载,请注明出处:http://www.gamelook.com.cn/2020/12/407368