近期,Unity在北京、成都、深圳分别举办了三场制作人专场活动,搭建优秀游戏制作人与Unity官方面对面交流的桥梁,内容涵盖项目优化、技术美术与解决方案等多个方面。
本文为大家带来的是Unity技术支持工程师刘伟贤的演讲-《Unity的超大开放世界解决方案》。你可以点击[阅读原文]下载本次演讲的PPT。
下面是本次演讲视频。
演讲内容
大家好,很高兴这么多人在场聆听,首先简单介绍一下我自己。
我是刘伟贤,是Unity在广州的技术支持工程师,主要负责企业级技术支持的工作,服务过很多企业客户。
今天,我为大家带来的演讲是《Unity的超大开放世界解决方案》,在座的不少人是开发移动端游戏的,所以我的演讲内容将着重面向移动端的解决方案。
首先,向大家介绍一下我分享这个项目立项时候的一些情况。
立项目标是使用当时比较新的Unity 2019.1版本,游戏类型类似《绝地求生》,游戏具有长视距和开放世界的元素。
我们设定摄像机为自由视角或锁定第三人称视角等。对于其它类型的摄像机,我们在有需要的时候也会尝试一些实现。
关于目标设备,我们主要面向是三星Galaxy S9和iPhone 8及以上的设备。游戏运行的目标帧率是30帧。
对于移动端,我们选择使用的是轻量级渲染管线LWRP,但是实际上我们也实现了基于高清晰渲染管线HDRP。所以整个大世界的解决方案,我们已经覆盖了LWRP和HDRP。(小提示:LWRP目前已改名为通用渲染管线URP)
为了保证客户可以更好地接入这个方案,绝大部分脚本的实现都是基于C# source package,也就意味着大家可以即插即用,非常简单。
游戏世界大小方面,我们是最小以4K×4K的世界。关于表现相关的部分,我们觉得风格化的也可以,但是暂时还没有做更多照片级的真实渲染,我们也借助了一些外部的工具来完善整体的流程。
总体来讲,整个超大世界的方案中,我们有下面的这些功能。
首先是使用HLOD System + Terrain HLOD System,可以替代很多静态的Mesh网格,把它们进行合批和减面,达到一个在长视距的时候能够有比较好的内存和性能的指标。
关于Shadow Map阴影贴图,我们使用内部最新的Voxelized Shadow Map,它基于稀疏体素八叉树的算法,可以转换高分辨率的Shadow Maps阴影贴图。
在美术和设计的工具方面,我们采用了Houdini,来配合Unity做一个超大世界的地形的生成。例如:道路、树木、桥梁、石头的生成等。
Streaming流式加载是基于我们的HLOD System,里面会涵盖到我们的预制件、纹理、网格等。我们选用较新的Unity 2019.1这个版本的时候,也是考虑了Texture Streaming纹理流式加载等这些引擎后面提供的新功能。
还有Occlusion Culling Streaming,因为对于一个超大世界来讲,如果想要提高剔除效率的话,可以利用Occlusion Culling提前进行跟遮挡相关的剔除。对于超大世界而言,可能烘焙下来的离线数据量比较大,所以我们提供了Streaming的方式去做流式加载。
Light Probe Layout Tool和Light Probe Streaming是跟我们Lighting Occlusion光照剔除相关的工具,主要功能是自动化地排布Light Probe光照探针,并且在制作超大世界的时候,我们对光照探针做了一个Streaming的工具。
最后是Indirect Draw,简单来说就是充分利用CPU的资源去做Culling剔除、Indirect Instancing之类的操作。
下图左边的一二列跟上一页是一样的,我希望大家可以了解一下右边的列,这是兼容性方面的内容。
对于Unity 2019.1之前的一些版本,例如:Unity 5.6的版本,可能要了解这部分。但在Unity 2019.1之前的一些版本中,有一些HLOD System是可以兼容的,但Voxelized是没有办法兼容的,因为这在引擎中做了一些改动。
Houdini + Unity的流程是可以使用的。
基于HLOD System的Streaming流式加载,因为它是基于Addressable Asset的,所以在Unity 2019之前的版本,可能要自己实现基于Asset Bundle的Streamer。
这里有一点小改动,Occlusion Culling也是可以兼容的,Light Probe Layout Tool和Light Streaming的兼容都是完全没问题的。
Indirect Draw方面,目前无法支持我们的渲染管线。
对于整体的Solution Item解决方案部分,我会按开发的流程去讲:首先是如何得到这个场景,得到这个场景之后,如何把这个超大场景管理起来,场景管理起来以后,Lighting Solution光照解决方案是怎么样,如何处理光照和影子等。
然后,我们还要处理场景里面很多地表上细节的物体,下面我会详细讲解一下。
首先是Houdini + Unity Workflow工作流程。因为我是技术人员出身,所以对于美术相关的事情,更多地会去求助技术美术或其他的技术同事。
在开发超大世界的时候,很难有很多人员去参与超大世界的搭建,所以我们需要使用Houdini去生成地形,能够有路、有河、有桥等。生成完之后,导入到Unity中,就可以很方便地在Unity里面对这些参数进行调整。
当我们把这些东西都调整好,得到一个超大场景的时候,我们就可以进入到HLOD System进行预处理的状态。当到HLOD System预处理完了之后,我们就可以得到在观看时真正去运行的状态。
借助Houdini,我们可以快速进行Demo验证阶段和技术验证阶段,很快得到比较方便的模型。
下面介绍HLOD System对于场景的管理。
首先,HLOD System主要的目标是为了减少Draw Call。然后,进行更多的Batch批处理,
其次,减少面数和纹理,来使用不同的LOD Level。这些Draw Call减少、Batch提升以后,我们也对面数贴图和材质做了减法,这样我们相应地节省了内存,并提升了加载时间。
目前,HLOD System只针对当前所在的地方进行加载,它会流式加载网格和纹理,在后台进行异步的操作。
大家可能会问:HLOD System和原来使用的LOD有什么差别?
如下图所示,这是HLOD System和LOD的对比图。
HLOD System和LOD两者有一个共同的特性是:都可以做一些减面的操作。
当我们把面数减下来之后,LOD不能减少Draw Call和Memory Usage,也就是不能减少内存,LOD也不能提升CPU的开销,特别是在Culling和LOD的计算上。所以我们开发全新HLOD System来弥补这些方面的不足。
下图可以直观的展示LOD System和HLOD System两者之间的差别。
例如:最左边的图是最终效果,如果我们能看Draw Call的话,就算我们用不同的LOD等级,可能它的Draw Call都像中间这张图一样,它会需要很多Draw Call来把场景画出来。使用HLOD System以后,它可以最终只使用一个Draw Call来把场景画完。
下图是我们开发HLOD System时的一个测试场景,这里的Batch数量原来有5642个。
如下图所示,在我们使用HLOD System后,Batch就变成了952个。
下图是性能上的对比情况,使用HLOD System后,Draw Call从5642个降到了952个,占比降到了原来的16.87%。三角面数也从原来的8M降低到3.9M,是原来的50%左右。
HLOD System整体的流程是怎样的呢?
如下图所示,我们最开始从Houdini导入了一个场景到Unity,我们会在Unity转换为游戏对象,然后再得到预制件,这时候我们会进入到HLOD System,HLOD System其实最重要主要有四个阶段。
首先是Splitter阶段,我们要把嵌套预制件根据树型结构进行切分。
切分之后,Simplifier阶段会去做减面的操作,我们会根据不同的Leaf叶子节点,来判断这是较高等级的节点,还是较低等级的节点,来进行减面的操作。
当我们根据不同的LOD等级进行减法之后,我们进入Batcher阶段进行合批处理,对低等级的根节点进行合批的操作。
最后是Streamer阶段,我们会把它导出为预制件,通过Addressable Asset进行Streaming的操作。
这也是为什么经过HLOD System以后,我们可以把Draw Call合批到一起的原因:我们对整个场景进行了树型结构的整理、检验和批合,最后通过Streamer阶段进行流式加载。
在Runtime运行时的时候,HLOD System要做的事情就比较简单。因为我们大量的工作都已经在预处理阶段处理好,所以在运行时的时候,我们只要在Camera PreCull的时候,进入HLOD System更新Culling的数据,选择要显示的是低精度的节点,还是高精度的节点,还是把它隐藏掉。
这跟原来LOD System有很大的差别。如果使用过原来的LOD Group的话,虽然LOD可能分成了很多等级,但里面的网格其实已经进入内存了,只节省了渲染的开销,依然无法控制Culling。
HLOD System会从根源上解决很多问题,它可以精准地把需要的内容渲染出来。
创建超大世界,有一个很大的难题:Lighting Solution,也就是光照方面的问题。
目前Unity内部采取的是LightProbe baking + VSM(Voxelized Shadow Maps))+ CSM(Cascaded Shadow Map)的解决方案。
VSM体素化阴影贴图是给长距离大范围的空间使用。对于近距离的物体,我们还是使用原来的CSM级联阴影,来达到更好的精度。对于远近景物的融合,我们希望可以达到比较协调的状态。
Voxelized Shadow Map体素化阴影贴图的工作流程非常简单,我们会在离线时做数据的处理,也就是基于稀疏的八叉树的体素化算法来离线处理数据,生成高精度的阴影贴图。
在运行时,这跟原来没有太大的区别,但是中间有一步是Screen Space Shadow Compute Pass,这里我们会使用Compute Pass进行一些跟计算相关的事情。
下面是一个效果图,包含了静态物品和动态物品融合的状况。
我们可以看到Voxelized Shadow Map体素化阴影贴图,在不同的分辨率下的构建时间和占用内存的大小。这是展开的大小,因为对高体来说,其实还可以进行数据的压缩,来降低这部分数据。16K指的是分辨率。
下图是将VxShadows放到HDRP里面,进行体素光照的展示。
刚才讲到了关于阴影的部分,除了阴影以外,还有渐进光相关的一些事情。我们在这主要靠光照探针的贡献。
如果大家用过光照探针的话,就知道对光照探针最麻烦的事情是要手动去布点,往往在光源变化比较大的地方进行手动密集布点。但是这样做的话很累,因为需要不停地布点、修改和Bake烘焙。所以我们提供了两个工具:LightProbe Auto Layout Tool和LightProbe Streaming。
LightProbe Auto Layout Tool提供了方便的方式,来生成大量的光照探针,替代人工放置的操作。
LightProbe Streaming会把光照探针数据切分为不同的区域部分,在运行时进行流式加载,确保不需要把大世界的光照探针数据都放到内存里面。
下图是LightProbe Auto Layout Tool工具的截图。这个工具是我开发的,左边的图是其中一个样式,我们可以点一下按钮,让它自动生成光照探针的排布。
LightProbe Auto Layout Tool有非常简单的工作流程,首先它提供一些Generator,这些Generator是排布的规则,里面提供了五种排布的规则。
第一种是基于网格,按照AABB一个个点来排布。
第二种是对于没有LOD等级的网格,对网格进行包围的计算,它有一定精度的数值,控制光照探针如何精准地包围产品的物件。
第三种是基于LOD Group Mesh的Generator,在排布光照探针时,我们会基于哪一级的LOD来进行排布。
第四种基于Light的Generator,它可以在光源变化的地方,比较密集地排布光照探针。经过我的试用,这种方式非常好用。
第五种是基于Terrain地形的Generator,在Unity 2019.2中,我们的光照探针已经支持让静态物体和动态物体同时受到光照探针的影响,所以使用光照探针做这样的方案是没有问题的。
这几个Generator可以组合使用,并不是只能单独使用其中某一个。
当排布好光照探针之后,我们会提供Optimize Baker。在烘焙的过程中,我们不需要生成Lightmap光照贴图,我们只需要把间接光这类低精度信息烘焙到光照探针就可以了。所以我会提供优化后的Baker,来把光照探针烘焙出来。
烘焙完成后,我们会提供专门用来做优化的Optimizer。毕竟这些是自动化排布的探针,而且是组合使用的结果,所以难免会产生一些小问题,例如:光照探针之间非常接近,光照探针在物体里或地底下。
因此,我们提供了Optimizer来进行光照探针的裁减,把烘焙完的差异较小的探针剔除掉,并且把全黑的光照探针也剔除掉,最终达到的效果是:有比较合理的光照探针存在场景中。
最后一步是进行切分,然后进行流式加载。
刚刚说完了我们的Lighting Solution光照解决方案,现在讲一下场景里面的细节物体。在游戏里面,细节基本上是大家非常熟悉石头、树、草、植被等。
对于Render System渲染系统,我们最主要做的两件事情:第一件是使用GPU去做世界的Culling剔除,第二件是使用Indirect Instance Draw把细节画出来。
听起来似乎很简单,但是实际上在系统里面,我们加入了四叉树,在传递到GPU之前,我们还会进行简单的裁剪,以及针对树的优化。如果我们把每棵小树作为个体,这个数据量还是蛮大的。因此,我们后续还有调整的方案。
关于Occlusion Culling Streaming,我们沿用了原有的Occlusion Culling遮蔽剔除功能,然后我们给它加上了Streaming流式加载的功能,基本上,它是对烘焙好的Occlusion Culling数据进行Streaming的操作。
对于未来Roadmap路线的话,我们的研发人员还在开发一些新的功能。
例如:使用Virtual Texture对超大场景的地形进行支持,然后Terrain System地形系统也有全新的基于Clipmap的系统。
在光照探针这块,研发人员也在进行对Light Probe Data光照探针数据进行重新编码,把数据存在一张纹理里面,使其得到更高的精度。毕竟从光照探针到光照贴图的精度差异是有点大的,所以我们使用折中的方案来提升这方面的精度。
下面给大家看一下目前我们基于HDRP的技术Demo。
大家可以看到下面还有一些红色的技术报错信息,因为这些内容还在开发阶段。Demo里的素材可能看起来不是很炫酷,但它只是一个技术的验证。
这是目前我们在制作的技术Demo,把整个大世界放到HDRP里面,其实整体技术方案对LWRP和HDRP来说,基本上全都适用。目前我们用的版本是Unity 2019.1.7f1。
除此以外,其实我们也给其它行业做了跟大世界相关的事情,例如:这是我们做的智慧城市,这也是偏技术Demo的内容,里面包括:建筑物、道路、树木等等。
目前,我们这一套大世界的方案,除了我们跟很多客户在合作以外,在其它一些行业和领域都有使用场景。
我今天的分享就到这里,谢谢大家。