游戏中那些细节丰富的野外场景是如何做出来的?看完这篇你就懂了
The following article is from NExT Studios Author 引擎全开的
编者按 “过程化内容生成”也叫“程序内容生成”(Procedural Content Generation=PCG),是一种自动为游戏、模拟或电影创建数字资产的方式,可以大大提高内容生成的效率。NExT Studios 在使用虚幻引擎4开发《重生边缘》(SYNCED:Off-Planet)的过程中,在过程化生成场景方面进行了一些尝试:除了介绍各种生成内容的思路外,还分享了针对过程化生成工具加入场景制作后,如何解决新的工具在实际工作中遇到的各种问题,以及一些实验性工作分享。
作者:NExT Studios
(本文内容由公众号“NExT Studios”提供,转载请征得同意。文章仅为作者观点,不代表GWB立场)
有了植被的区域后,我们可以在区域中进行撒点操作:一种操作是直接在区域中进行随机撒点,另一种是围绕某个目标点周围进行随机撒点。我们可以在第二种情况下生成伴生的灌木,一般情况下我们不可能一次只生成一种植被。
通过这样不断迭代,我们可以获得非常均匀、没有互相穿插的效果。但在不同的树种之间(例如高大的树木和低矮的灌木间),其实可以有一定的穿插,这是我们定义外半径和内半径的原因。对于大地图上的不同的区域,会有不同的生态分布。我们可以通过全地图刷mask来区分我们每一部分使用怎样的生成规则。比如说在海边,我们会以一些草地沙石为主,山上则以森林为主。
• 我们先有大概的曲线,根据地形高度图做自然滑落。相当于把一条绳子扔在地表上,它会自然地弯曲;
• 有些地方地势比较高,我们可以挖一条河道,这时会改变地形的高度;
• 因为我们不想生成过大高度差,从高地往低地过渡时,我们需要形成多级小瀑布;
• 然后我们根据河流的地形地势分布和弯曲度,生成河面河道宽度的变化。
• 最后我们在河道里撒上一些碎石和水花去装饰,并生成河流的流向。
• 支流跟主流交叉的地方,可能高度并不一样,我们需要对齐高度;
• 有可能下游高于上游高度,这时候需要用下游的高度去往上游去做修正;
• 转折度较大和多个支流交叉的区域,我们不可能生成很多层的河面的mesh,所以做平滑处理,从平滑后的河道形状提取出河面,再对河面mesh进行切割和减面,这样对性能的优化很有帮助。
生成完河道后,地表的纹理会随之变化,我们可以铺设鹅卵石,或在河岸边缘生成潮湿泥沙的效果增加河岸表现,生成相应的植被分布增加细节等。
我们使用Unreal Landscape Spline的内置功能来对河流进行曲线编辑,因为它比较符合美术的操作习惯。我们先拖拽出河流经过的区域,然后编辑各个支流大致的路径,设置每条支流的起始点,之后一键生成。这时候我们可以根据地势做自然弯曲,挖出河道、生成地表的纹理,生成河面的mesh,还有河面流向的数据,包括水花、石头等等。
实现的思路就是使用海量贴花(在 GDC 2017 的 Ghost Recon Wildlands: Terrain Tools and Technology 中有类似分享)来实现,包括路面的破损、道路中间的车轮印、车道标记、水迹效果、路边的落叶的尘土的效果,都是通过贴花的方式来实现的。但裂缝里长的草不是贴花,是在生成裂缝贴花的时候,顺便把裂缝草的位置一起计算出来。
还有一个比较实用的功能,用Unreal Landscape Spline做道路的时候并不能很好地处理交叉口,我们生成了任意角度交叉口的贴花,掩盖了衔接处的接缝问题。
另外我们在道路曲线计算完毕之后,可以根据道路曲线的分布来调整地表的权重分布。比如我们可以在道路的周边去生成相应地表的过渡效果(裂缝、草、破损尘土、水迹、路口交叉口车轮的印记),另外还有道路的附属物(比如护栏、电线杆)等。
20:17 过程化内容生成中容易遇到哪些流程问题?
比如生成的效果达不到美术的要求;工具的使用门槛太高,他们不想用;工具不够稳定,他们觉得折腾的成本太高;或者涉及多人协作的问题,这个事情到底是程序员做、TA做、还是关卡美术做?多个关卡美术的协作需求如何解决?等等。只有解决了这些问题才算是一个合格可用的工具链。
基于前面的分享,相信大家也能看出,我们的目的是:并不追求全地图自动化生成,而是根据需求做一些定制,提高制作效率。
过程化内容生成管线
21:35 自动生成内容和人工编辑内容之间的冲突问题如何解决?生成内容之间的关卡切分问题如何考虑?不同子关卡的生成限制如何保证结果的稳定性?
我们总结出来两个原则,第一是生成的内容不能覆盖人工编辑的内容。第二是各个子关卡之间尽量地独立地编辑和生成。就像 Unreal 大世界里的地图,通常会编辑成多个子关卡,方便多个美术协作,然而对于过程化生成的内容,也需要去做这样的支持。比如可以对world composite做一个支持,支持地形自动切分到子关卡。
自动切分到子关卡
关于生成的内容(大量贴花、崖壁、河流等)之间,也都需要切到子关卡。只有切分了子关卡,才能做独立地剔除和 level streaming,同时也能支持不同的人来编辑和生成不同的子关卡。
对于不同的子关卡,我们生成的限制是需要保证结果的稳定性:不管是多块一起计算出来的结果,还是单块单独计算出来的结果,应该是一致的。这样才能够保证按照子关卡的方式去工作。
23:14 地形和建筑的稳定性如何解决?
对于地形来说,我们没办法很好地解决。因为关卡与关卡之间会有一道必然的交界,如果只更新了其中的一块,另外一块就接不上了。
虽然可以对整个地形做整体的侵蚀或美化,做一次全量更新,但这对于整个开发来说是非常不友好的行为,因为需要协调所有人,把所有的关卡文件都解锁。我觉得更实用的做法是做局部的更新,比如只更新刷过mask的区域。
局部更新mask
对于有些建筑区域,比如某处建了一栋房子,要求地基是平的,我们不想在生成地形的时候改变地表,很可能房子就悬空了。我们可以使用volume把区域框起来,跳过这个区域的侵蚀生成。
volume排除侵蚀区域
24:32 跟美术编辑的冲突问题如何解决?
有时候过程化生成的内容跟美术编辑的内容在同一个数据集里面,就会产生冲突问题。到底用谁的呢?Unreal提供了Edit Layer的功能,它跟Photoshop的图层一样,可以把生成的单独放一层,人工编辑的单独放一层,甚至还可以开更多的层,这样就可以混合人工编辑和我们生成的数据,得到想要的效果。但有的时候可能并不想要混合效果,而想要替换效果(比如说河流河道可以替换掉原有的地形)。我们又开发了一个Edit Layer的覆盖混合模式,用来支持这样的需求,同时也扩展了Unreal权重绘制的工具,用来绘制mask,支持这种覆盖混合和很多层的表现。
Edit Layer覆盖混合模式
还有一种冲突比较常见,比如说美术在某处放棵树,只是用来做装饰的,但是我们生成植被的时候很可能就把这棵树给生成没了,那这不是他们想看到的。所以我们针对生成的树都会打标记,每个instance上都会有一个特殊的属性,这样就能够区分出来到底哪些树是我们生成的,哪些树是美术编辑的。再重新生成的时候,就可以把原来生成的树全部删掉,做一次全量更新,但美术摆的树并不会被删掉,而且也可以选择避开他们。
很容易树没了
26:13 数据导入导出的问题如何处理?
我们沿用了Unreal Landscape Spline曲线生成,这些数据需要导出到Houdini当中进行运算,其实这也是为编辑的操作习惯而做的妥协,也避免了再开发全新的一套曲线编辑工具。
我们把Unreal Landscape Spline重新做了算法量化,导出成一个 JSON,然后在Houdini当中提取这些关键点做重建,这样就可以基于这条曲线去做算法实现。我们也加了各种各样的自定义属性,比如说曲线的类型,因为它会有不同的内容(路、护栏、河等),他们是属于不同曲线的。曲线的宽度还有优先级也都是通过这种方式添加到 JSON 文件里。
针对生成的内容。我们也做了一个简单的热力图扫描工具,可以选择任意一个Unreal当中的某个stat,比如针对面数去做统计,生成可视化的表现,方便美术在生成完或者关卡编辑完后去做性能自查。
热力图性能分析面板
28:01 一些试验性的探索
如果只是针对之前提的那几个功能的话,可能整个工作流是大同小异的,但是每个项目其实需求都不一样。比如说有的项目完全不用Houdini,生成算法全在Unreal里程序员自己实现。还有的项目可能因为不喜欢数据互相导来导去,选择整个的关卡布局是在Houdini当中进行制作,然后再导入Unreal,这个时候就不能改了。还有的像我们一样,频繁导入导出,需要很多数据交换,那我们需要程序员不断地处理这些特殊的需求。
所以我们在把这种工具推广到不同项目的时候,就需要重构整个管线。我们支持了蓝图节点编辑,让原来Houdini的HDA文件生成一个蓝图的异步节点,其所需要的数据准备是通过蓝图来进行的(包括数据输出的后处理),这样就具备了非常高的灵活性,能满足很多奇奇怪怪的需求。
可定制的生成流程
我们生成完,可以给它打个 tag 或者设置一些类似 virtual texture的属性,然后生成一个actor,甚至改变它的材质。在这套机制下,解放了程序员的生产力,不用他们专门开发特性。因为有的时候我发现不是这些功能实现不了,而是美术等不了,或者用户等不了,反复折腾的时候他们就不想用了。
另外,我们把数据的输入输出做了抽象,比如抽象成图,或者曲线,或是一些点,然后把这些数据做了抽象之后,甚至可以通过网络来传输这些数据,把生成的服务放到一台更强健的GPU工作站上。而且把数据做完抽象之后,也不限于只用Houdini来做,可以搭建一些自己的服务,用 Maya或Blender也都可以,因为数据的交换变得非常简单。
生成服务器
我们也做了些机器学习的一些尝试,比如说基于GAN算法的现实世界生成,或者是地表地形的风格化迁移等。还有一个很常见的问题是在用Houdini做这些工作的时候,数据的导入导出和计算都需要非常长的等待,有些团队会倾向于在引擎中自己实现生成算法,我们在这方面也做了一些简单的尝试,参考了《地平线:零之曙光》(Horizon Zero Dawn)的做法,使用GPU加速的方式做地表地形的生成和植被的分布。
过程化内容生成的技术除了应用在游戏开发中,还有其他应用场景。例如NExT跟新华社合作的数字航天员小诤的火星视频中,我们使用了过程化内容生成的技术模拟火星的地貌。UE5的Nanite可以在不限制三角形数量的情况下做大量的几何细节,这应该也是后续游戏制作的趋势之一。