|
为期四天的腾讯游戏开发者大会(Tencent Game Developers Conference , 简称TGDC)已于12月7日在线上正式召开。
在昨晚的主题演讲上,腾讯互动娱乐《天涯明月刀》手游引擎负责人刘冰啸以「用技术诠释国风浪漫的归去来——《天涯明月刀》手游开发历程」为主题,分享了《天涯明月刀》手游如何在移动端平衡画质、帧率与功耗来诠释国风浪漫的。
为提升阅读体验,内容有删减和调整:
大家好,我是刘冰啸,是《天涯明月刀》手游引擎的技术负责人。这次主要分享一下《天涯明月刀》手游开发历程中几项关键点的技术决策和开放经历。
1.手游引擎开发三要素
手游引擎开发需要考虑几个重要要素。
首先是画质。这点可以进行一些选择,比如是希望它突出远景,还是突出近景?希望它是优于室内,还是室外?希望整个画面效果是鲜艳,还是更加自然?是优先光线的表达,还是优先影子的效果?
第二是帧率。对天刀手游这种强交互性的MMORPG游戏,我们需要一个高而且稳定的帧率。
通常我们在PC开发的时候,只需顾虑两个方面:先达成一个画质的效果表现,然后通过优化不断地提高帧率;帧率达成一个目标点后,再想办法引入更好的画质表现,两者再不停地迭代。
而手游,我们还引入了第三个维度——功耗。对手机来说,这是一个非常重要的维度,不仅会产生发热,而且还会影响到你游玩的单次时间。
在这三个维度上,对其中任何一个维度的增加,都会影响到其它另外两个维度的表达。
2.手游优化
对天刀手游的优化来说,开发引擎组采用了各种各样的技术栈获取更好的优化效果:
对多线程渲染引擎进行了优化,把大部分可以并行的工作,比如动画、布料,都放到其它的线程中进行运行;
使用了ISPC自动生成NeonSIMD的代码,可以更好地提升CPU的执行效率;
在GPU和CPU的遮挡剔除中,使用了不同粒度的遮挡剔除算法;
首先启用了Vulkan API,通过它对GPU的内存进行更好的粒度上的管理;
实现GPU driven的渲染管线;
用computer辅助优化各项其它的渲染技术;
画面上采用PBR材质和真实物理单位的lighting。
我们在每次测试中都会进入一个重要的优化。
在第一次测试中,我们对unity进行了多线程的框架改动,把渲染线程和提交线程从主线程中剥离出来。因为在手游的开发环境里面,一个主要线程的持续工作,会带来手机芯片的功率提升,这会导致更加严重的发热。
在第二次测试中,我们引入了Vulkan API。相对GLES来说,Vulkan API有着更好的、更轻量级的调用。经过测试,我们可以做到在提交线程上获得30%的CPU的效率提升。
在第三次测试中,我们引入了GPU driven技术。通过它可以把大部分CPU上的工作转移到GPU上去运行,不仅提升了GPU的效率,也减少了从GPU到CPU之间的各种传递的带宽。这项技术主要运用到地形、植被和家园系统里面。
三测时我们还修改并提升了整体的光照表达,引入了自动曝光,提升了Tonemapping的效果,解决了由于真实物理单位引入之后,在不同的关照环境下lighting体现的一些细节的颜色丢失问题。
我们重新对sky lighting进行了定义,使得整个场景的室外表现更加丰富且具有对比度。
3.GPU driven技术优化要点
接下来主要分享一下我们采用GPU driven技术对渲染技术进行优化的一些要点。
在开发过程中,我们经历了多线程的优化,发现了手机平台上一个优化的甜区:其实手机的多核,要比我们在端游时代更早的进入了多核时代。现在安卓手机很多都是四加四的多核架构,有点像上一代主机平台上看到的,在这些架构下,能让开发者更多地使用这些辅助的计算单元来提升计算效率。
我们引擎组采用了两个方向。一个是尽可能地剥离主线程上的计算,通过dispatch到其它线程上来提升它的计算效率;另一个是把计算转入GPU compute,它相当于现代渲染框架的一个基石,除了GPU进行光栅化处理的部分之外,compute能够完成大量的GPU渲染流程上的操作。
值得注意的是,compute的渲染语言其实完全能和GPU本身的硬件对应起来,例如里面的Local Data Storage机制,ThreadGroup和Thread利用率的概念。
另外就是使用compute能发挥Vulkan更大的潜力,因为我们可以使用后者对GPU的同步行做出非常好的控制。
Compute作为一个独立的单元,可以很好地把它的计算和GPU的其它计算并行起来。另外compute还是一个单独的Queue,对比vs和ps的整套pipeline,它是一个非常简化的单元,容易随处摆放。
采用compute可以给GPU driven和Bindless打开更广阔的优化空间,甚至可以使用Async compute方式进一步并行compute和GPU的单元。
对天刀手游来说,打开compute的关键突破点,就是GPU driven的地形系统。
先看一下行业的发展方向。在最近几年,GPU driven其实是一个相对比较热门的研发方向。在SIGGRAPH 15上,育碧有一篇关于GPU driven的渲染管线的文章,主要将《刺客信条:大革命》的开发;2016年GDC上,EA的寒霜引擎也提到了GPU driven的pipeline;2018年,育碧的《FarCry5》也实现了相关的功能。
再讲一下GPU驱动的渲染管线。它是GPU掌握实际的渲染控制,可以提供更细致的渲染力度。例如在做渲染剔除的时候,CPU只能控制在object level,使用Object Bounding做剔除,但在GPU层面上,我们可以做到更进一步的控制,在Mesh cluster级别上,通过切分Mesh来获得更好的力度控制。
它的另外一个好处是不需要GPU和CPU之间的数据来回传递,在理想的情况下,GPU driven甚至可以使用一个Drawcall绘制完成整个场景。当然,这个需要compute shader的支持,已经indirect drawing相关API的提供。
接下来看一下在天刀手游里,GPU地形实施之后的结果。
在这之前,先介绍一下CPU地形常用的算法。我们上一个版本里面的地形算法是CPU端的Geometry Clipmap算法,它采用视锥裁剪剔除方式;对比GPU driven,少了depth剔除;计算LOD的方式是根据距离计算的,而GPU driven可以根据距离和地形块的复杂度来计算。
送入clipmap方式的顶点处,因为有两个pass,其中一个要通过Virtual Texture来使用,这样就需要21万乘2的定点数。而在GPU driven的情况下,因为获得比较好的剔除效果,只需要8万6的顶点数。
再看一下GPU时间。在GPU driven的情况下,在iPhone8P上可以获得2.9毫秒的时间开销,这比通过CPU的方式节省了近四分之一的成本;而在CPU端获得的收益更大,提交线程和渲染线程每个都可以获得5毫秒以上的收益。
GPU driven的流程主要包含GPU driven和Virtual Texture两个算法,彼此的实现有互相交叉,出于简化,接下来只讲一下GPU driven。
首先是一个深度mips生成,这部分算法是在compute里面实现的;
其次,我们是在compute里面实现GPU遮挡剔除,它主要通过计算你所送入的patches的尺寸,看它处在哪一级的深度缓冲上,再对比这一级深度缓冲的深度和你的深度,来决定是否被depth剔除掉;
通过这个流程,我们可以获得可视的patches数目,据此通过compute做indirect的Arguments buffer生成;
最后是把这些准备好的indirect buffer绘制出去,这就是整个地形GPU driven的渲染流程。
其中有一个非常重要的优化,主要是利用compute里面的Thread shared memory方式,减少了CPU到GPU之间的多次dispatch,也减少了binding memory pingpong操作。
它能应用的范围主要在于对buffer做filter,例如我们经常在渲染管线中提到的Bloom、高斯模糊、自动曝光,这些对于区域进行filter的操作,都可以采用这些方法来获得优化。
在天刀手游中,我们会做第一次的dispatch,它会产生16*16的线程组,每组128条线程,这128条线程读入深度,然后放入mips里;第二步通过同步的方式,再把上一级mips相邻的四个点取出来,合并选择最深的单位,写到第二级的mips里,以此类推,完成四级的写出。
在第二个dispatch里,我们用同样的方法dispatch一个线程组、128条线程,同样把后面32*16的mips写入完成。
我们还有另外一个机制需要优化,那就是LOD体系。
在《FarCry》的实现里面,它主要采用的是CPU四叉树的方式来组织LOD的patches,根据距离更新四叉树上的节点,然后根据相机的距离选择这些节点,送入GPU进行indirect buffer和GPU Culling。
而天刀手游则把这些patch信息先通过offline的方式bake出来。我们在每一个相机发生位置变动的时候,会去更新这些bake出来的信息,再根据这些信息对改变的patch做过滤,然后生成新的indirect buffer。
在我们完成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或者是bindless都没办法获得更好的支持。所以在天刀手游的实现里,我们只能将草的每种类型完成一次GPU driven的culling和Driven Indirect Buffer的生成。
在天刀手游里面,比较适合GPU driven的另外一个场景是家园的渲染。家园玩法要让玩家尽可能地定制整个家园的地形、地表、墙壁、地板、物件等等,它需要非常多的geometry类型;再者它的区域相对比较小,只有128米*128米的自定义空间,在这种情况下,遮挡剔除必须要做得非常好。综合这两点,GPU driven是最适合的。
问题在于,家园里的这些物件,其实和草的类型一样,非常依赖Multi Draw Instanced Indirect和bindless这两种API的实现。
对天刀手游来说,我们只能退而求其次,利用地形步骤算出来的HiZ的buffer做遮挡剔除,送入一套做遮挡剔除buffer的内容,通过CPU从readback的方案来获得这些buffer的遮挡剔除的结果,然后在CPU端组织尽量多的instance对象。
Q&A
1.性能优化有什么技术难点?听说你们能以更低的规格实现更高标准,是怎么做到的?
我们在实现的过程中,没有特别去顾虑高规格和所谓的低规格,一般是设定一个标准,然后在这之上找一些平衡。举个例子,前面提到的光照或者阴影表达,我们认为阴影的表达是弱于光照效果的,所以我们仍然采用了比较传统的lightmap来bake shadow的方式,在大世界里面并没有使用实时的阴影。
这其实更像一个平衡的问题,要基于你的游戏本身去承受的技术点,优先选择面,最终达成一个适合你游戏要求的技术方式。
2.像《天涯明月刀》这类从端游移植到手游的经典IP,从引擎技术角度如何更好地还原端游品质?
这个问题要从两方面回答。
一方面,明确我们需要去还原端游的哪些特点。这个对我们游戏的选择还是十分明显的:第一要更加注重远景的表现;第二要有更好的角色表现。
另一方面是基于以上这些,我们要从端游还原到手游上的一些画面技术点,我们会去制定关键的技术要素,例如我们延续了端游的PBR管线,但使用了比端游更好的基于物理光照单位的一个lighting方式,使得我们的手游在暗光的情况下表现非常好。
以上就是我今天的所有分享内容,谢谢各位。
整理:手游那点事
地址:https://mp.weixin.qq.com/s/i11G_ZQvPp5-45ySB9pDrQ
|
|