以下内容来自:NExT Studios
“过程化内容生成”也叫“程序内容生成”(Procedural Content Generation=PCG),是一种自动为逛戏、模仿或电影创建数字资产的方式,能够大大进步内容生成的效率。
NExT Studios 正在使用虚幻引擎4开发《沉生边缘》(SYNCED:Off-Planet)的过程中,正在过程化生成场景方面进行了一些尝试:除了引见各种生成内容的念绪外,还分享了针对过程化生成工具加入场景制作后,如何处理新的工具正在实际工作中逢到的各种问题,以及一些实验性工作分享。
《沉生边缘》主地图
主地图3x3公里,大约有 20 个 POI、16 层地表、9 万多棵树、30 多种植被、 20 公里长的路和 6 公里的河流。之前除了Unreal Editor之外,我们没有过程化生成的积累,正在加入过程化生成内容的时候,也不能覆盖已有的 prototype 关卡,同时需求兼顾关卡美术和关卡策划的操作习气(他们正在Unreal Editor中进行数据编辑工作,但过程化生成算法是正在Houdini中实现,需求导入导出数据),各个生成元素之间有必定数据依赖关系(比如河流改动会影响地形的高度图和材质层,地形高度图改动也会影响到植被的分布等)......我们面临许多应战。
我们开发了约30个工具,但由于场景中每个 POI 的风格和设念都非常不一样,较难提取一致的理性规律,所以工具的目的是调整关卡布局时,加快周边环境的建正,大部分的生成内容集中正在野外区域。
场景结构
地表侵蚀的作用?地表材质层的权沉分布如何计算?
把mask转成地形后做侵蚀美化是基础功能,侵蚀会改变高度图的表现,也会生成地表材质层的权沉分布。
侵蚀前后地形对比
地表权沉图是正在Houdini当中进行计算的,大概原理是:根据高度图的斜率计算出大体分布,然后配合例如雨水冲刷的成效,根据每一层的石头和沙地的规则,定义出不同的权沉图,然后导入引擎,就能够得到混合好的地表成效。
混合好的地表成效
垂直面地表崖壁岩石如何生成?如何正在地表上呈现更丰富的细节?人物卡进mesh里如何处理?
我们当时参考了一些业界材料,比如《孤岛惊魂5》(Far Cry 5)、《刺客信条》(Assassin's Creed)。一开始我们根据地形的坡度,提取它的区域转成mesh,然后生成UV,揭上我们念要的纹理后,用displacement map模仿了岩石表面的凹凸,但是近看的成效不理念。于是我们尝试了另外一种方案——mesh揭片。像揭瓦片一样,把固定的mesh来所需区域里反复粘揭,这样能够用比较低的面数达到更好的成效,由于它的几何细节会更多一些。
mesh揭片成效
正在生成崖壁的mesh的时候,崖壁下方和与地表过渡的地方,能够用与岩石纹理类似的地表材质来表现,因此生成了相当的地表材质权沉层。还需求处理生成的岩石与地表的过渡:生成mesh的时候,把权沉写到了顶点色里面,然后采样地形的纹理做平和地过渡。岩石下方我们能够生成一些碎石或砂石,这样会有更具细节的地表表现。
增加细节前后的岩壁对比
正在实际使用中还会逢到一些尴尬的问题,例如人物有时会卡正在生成的mesh里。这是由于Unreal根据不规则的mesh默认生成的碰碰体有很大瑕疵,这时我们会针对这些不是闭包类的mesh生成特地碰碰体,然后再一同导入引擎。
如何计算获得视觉均匀的植被分布?植被间距如何考量?如何进行撒点操作?
我们参考了《孤岛惊魂5》(Far Cry 5),这几乎是业界最精细的分享。我们的全体生态和植被组成是不一样的,我们选择的是温带针叶林。具体做法是:我们根据高度图生成各种各样的mask,再配合噪声模仿随机分布。正在此之上,我们能够把光照、风向和气候影响也考虑正在内,生成更多的mask,经过运算得到我们念要的分布。
有了植被的区域后,我们能够正在区域中进行撒点操作:一种操作是间接正在区域中进行随机撒点,另一种是盘绕某个目标点周围进行随机撒点。我们能够正在第二种情况下生成伴生的灌木,普通情况下我们不可能一次只生成一种植被。
两种撒点方法
我们针对每种植被定义了三种半径,用来防止树与树之间的沉合。根据这些规则,我们量化这些点的位放,让离得较近的点更易被判断。如果这些点都被包围的时候,我们无法挪动把它排除掉,我们就删掉它。
经过这样不断迭代,我们能够获得非常均匀、没有互相穿插的成效。但正在不同的树种之间(例如高大的树木和低矮的灌木间),其实能够有必定的穿插,这是我们定义外半径和内半径的缘由。对于大地图上的不同的区域,会有不同的生态分布。我们能够经过全地图刷mask来区分我们每一部分使用怎样的生成规则。比如道正在海边,我们会以一些草地沙石为主,山上则以森林为主。
滑动查看植被成效图
河流如何生成?下逛比上逛还要高如何处理?转机度大的河流如何处理平滑?生成完河道之后,地表的纹理细节如何调整?
正在《沉生边缘》中,河流是表现类的成效,不影响逛戏的玩法,所以过高的高度差、过深的水面都是策划和美术不念要的,所以我们期视做很浅的溪流。我们算法上也进建过《地平线》(Horizon)的分享,整个生成过程大概分成:
• 我们先有大概的曲线,根据地形高度图做自然滑落。相当于把一条绳子扔正在地表上,它会自然地蜿蜒;
• 有些地方地势比较高,我们能够掘一条河道,这时会改变地形的高度;
• 由于我们不念生成过大高度差,从高地来低地过渡时,我们需求形成多级小瀑布;
• 然后我们根据河流的地形地势分布和蜿蜒度,生成河面河道宽度的变化。
• 最后我们正在河道里撒上一些碎石和水花去装饰,并生成河流的流向。
河流生成过程
河道生成的其他问题:
• 支流跟主流交叉的地方,可能高度并不一样,我们需求对齐高度;
• 有可能下逛高于上逛高度,这时候需求用下逛的高度去来上逛去做改正;
• 转机度较大和多个支流交叉的区域,我们不可能生成很多层的河面的mesh,所以做平滑处理,从平滑后的河道外形提取出河面,再对河面mesh进行切割和减面,这样对功能的优化很有协帮。
如何减少河面流向图的内存占用?如何编辑河流的走向和成效?
对于河面的流向图,如果用全地图的flow map一张纹理来覆盖的话,会浪费非常多的UV空间。考虑到更高效功能和更低内存占用,我们把流向音讯写到顶点色里,只需占用两个通道。
生成完河道后,地表的纹理会随之变化,我们能够铺设鹅卵石,或正在河岸边缘生成潮湿泥沙的成效增加河岸表现,生成相当的植被分布增加细节等。
我们使用Unreal Landscape Spline的内放功能来对河流进行曲线编辑,由于它比较符合美术的操作习气。我们先拖拽出河流经过的区域,然后编辑各个支流大致的路径,设放每条支流的起始点,之后一键生成。这时候我们能够根据地势做自然蜿蜒,掘出河道、生成地表的纹理,生成河面的mesh,还有河面流向的数据,包括水花、石头号等。
滑动查看河流实际成效
裂缝长草、土路破损、路口过渡、车轮印记等道路上的“细节加分项”如何实现?多层揭花的优先级如何制定?
逛戏当中的道路基本是关卡策划正在编辑,它对玩法是有必定影响的,当我们加入做生成工具的时候,路网已有大约百分之八九十的完成度,所以我们并不是生成道路本身的路网,而是选择去增加一些细节“加分项”。比如裂缝长草、公路破损、不同道路之间的过渡、交叉口的车轮印记等。
实现的念绪就是使用海量揭花(正在 GDC 2017 的 Ghost Recon Wildlands: Terrain Tools and Technology 中有类似分享)来实现,包括路面的破损、道路中间的车轮印、车道标记、水迹成效、路边的落叶的尘土的成效,都是经过揭花的方式来实现的。但裂缝里长的草不是揭花,是正在生成裂缝揭花的时候,特地把裂缝草的位放一同计算出来。
还有一个比较实用的功能,用Unreal Landscape Spline做道路的时候并不能很好地处理交叉口,我们生成了任意角度交叉口的揭花,覆盖了连接处的接缝问题。
道路交叉口揭花
有了多层揭花,我们需求定义呈现层次的优先级问题,所以我们制定了“同级融合,高级覆盖低级”的揭花规则。全体的半透明材质的揭花数量加起来有数万个,有很沉的overdraw,会带来非常严酷的功能问题。所以我们使用了 Unreal 的Runtime Virtual Texture 来进行优化,把地表混合的结果跟道路和揭花混合的结果缓存到了一张巨大的虚拟纹理上面,能够大大降低地表绘制的开卖。
另外我们正在道路曲线计算终了之后,能够根据道路曲线的分布来调整地表的权沉分布。比如我们能够正在道路的周边去生成相当地表的过渡成效(裂缝、草、破损尘土、水迹、路口交叉口车轮的印记),另外还有道路的附属物(比如护栏、电线杆)等。
滑动查看更多路口成效图
下面将针对工具加入场景制作后,如何处理新的工具正在实际工作中逢到的各种问题,以及分享一些试验性工作。
过程化内容生成中容易逢到哪些流程问题?
比如生成的成效达不到美术的请求;工具的使用门槛太高,他们不念用;工具不够波动,他们觉得折腾的成本太高;或者涉及多人合作的问题,这个事情到底是程序员做、TA做、还是关卡美术做?多个关卡美术的合作需求如何处理?等等。只要处理了这些问题才算是一个合格可用的工具链。
基于前面的分享,置信大家也能看出,我们的目的是:并不追求全地图自动化生成,而是根据需求做一些定制,进步制作效率。
过程化内容生成管线
自动生成内容和人工编辑内容之间的冲突问题如何处理?生成内容之间的关卡切分问题如何考虑?不同子关卡的生成限制如何保证结果的波动性?
我们总结出来两个准绳,第一是生成的内容不能覆盖人工编辑的内容。第二是各个子关卡之间尽量地独立地编辑和生成。就像 Unreal 大世界里的地图,一般会编辑成多个子关卡,方便多个美术合作,然而对于过程化生成的内容,也需求去做这样的支持。比如能够对world composite做一个支持,支持地形自动切分到子关卡。
自动切分到子关卡
关于生成的内容(大量揭花、崖壁、河流等)之间,也都需求切到子关卡。只要切分了子关卡,才能做独立地剔除和 level streaming,同时也能支持不同的人来编辑和生成不同的子关卡。
对于不同的子关卡,我们生成的限制是需求保证结果的波动性:不管是多块一同计算出来的结果,还是单块单独计算出来的结果,该当是一致的。这样才能够保证按照子关卡的方式去工作。
地形和建筑的波动性如何处理?
对于地形来道,我们没办法很好地处理。由于关卡与关卡之间会有一道必然的交界,如果只更新了其中的一块,另外一块就接不上了。
固然能够对整个地形做全体的侵蚀或美化,做一次全量更新,但这对于整个开发来道是非常不友好的行为,由于需求谐和一切人,把一切的关卡文件都解锁。我觉得更实用的做法是做局部的更新,比如只更新刷过mask的区域。
局部更新mask
对于有些建筑区域,比如某处建了一栋房子,请求地基是平的,我们不念正在生成地形的时候改变地表,很可能房子就悬空了。我们能够使用volume把区域框起来,跳过这个区域的侵蚀生成。
volume排除侵蚀区域
跟美术编辑的冲突问题如何处理?
有时候过程化生成的内容跟美术编辑的内容正在同一个数据集里面,就会产生冲突问题。到底用谁的呢?Unreal提供了Edit Layer的功能,它跟Photoshop的图层一样,能够把生成的单独放一层,人工编辑的单独放一层,以致还能够开更多的层,这样就能够混合人工编辑和我们生成的数据,得到念要的成效。但有的时候可能并不念要混合成效,而念要交换成效(比如道河流河道能够交换掉原有的地形)。我们又开发了一个Edit Layer的覆盖混合模式,用来支持这样的需求,同时也扩展了Unreal权沉绘制的工具,用来绘制mask,支持这种覆盖混合和很多层的表现。
Edit Layer覆盖混合模式
还有一种冲突比较常见,比如道美术正在某处放棵树,只是用来做装饰的,但是我们生成植被的时候很可能就把这棵树给生成没了,那这不是他们念看到的。所以我们针对生成的树都会打标记,每个instance上都会有一个特地的属性,这样就能够区分出来到底哪些树是我们生成的,哪些树是美术编辑的。再沉沉生成的时候,就能够把本来生成的树全部删掉,做一次全量更新,但美术摆的树并不会被删掉,而且也能够选择避开他们。
很容易树没了
数据导入导出的问题如何处理?
我们沿用了Unreal Landscape Spline曲线生成,这些数据需求导出到Houdini当中进行运算,其实这也是为编辑的操作习气而做的让步,也避免了再开发全新的一套曲线编辑工具。
我们把Unreal Landscape Spline沉新做了算法量化,导出成一个 JSON,然后正在Houdini当中提取这些关键点做沉建,这样就能够基于这条曲线去做算法实现。我们也加了各种各样的自定义属性,比如道曲线的类型,由于它会有不同的内容(路、护栏、河等),他们是属于不同曲线的。曲线的宽度还有优先级也都是经过这种方式增加到 JSON 文件里。
针对生成的内容。我们也做了一个简单的热力图扫描工具,能够选择任意一个Unreal当中的某个stat,比如针对面数去做统计,生成可视化的表现,方便美术正在生成完或者关卡编辑完后去做功能自查。
热力图功能分析面板
一些试验性的探求
如果只是针对之前提的那几个功能的话,可能整个工作流是大同小异的,但是每个项目其实需求都不一样。比如道有的项目完整不用Houdini,生成算法全正在Unreal里程序员本人实现。还有的项目可能由于不喜欢数据互相导来导去,选择整个的关卡布局是正在Houdini当中进行制作,然后再导入Unreal,这个时候就不能改了。还有的像我们一样,屡次导入导出,需求很多数据交换,那我们需求程序员不断地处理这些特地的需求。
所以我们正在把这种工具推行到不同项目的时候,就需求沉构整个管线。我们支持了蓝图节点编辑,让本来Houdini的HDA文件生成一个蓝图的异步节点,其所需求的数据准备是经过蓝图来进行的(包括数据输出的后处理),这样就具备了非常高的灵活性,能满脚很多奇奇怪怪的需求。
可定制的生成流程
我们生成完,能够给它打个 tag 或者设放一些类似 virtual texture的属性,然后生成一个actor,以致改变它的材质。正在这套机制下,解放了程序员的生产力,不用他们特地开发特性。由于有的时候我发觉不是这些功能实现不了,而是美术等不了,或者用户等不了,反复折腾的时候他们就不念用了。
另外,我们把数据的输入输出做了抽象,比如抽象成图,或者曲线,或是一些点,然后把这些数据做了抽象之后,以致能够经过网络来传输这些数据,把生成的服务放到一台更强健的GPU工作站上。而且把数据做完抽象之后,也不限于只用Houdini来做,能够搭建一些本人的服务,用 Maya或Blender也都能够,由于数据的交换变得非常简单。
生成服务器
我们也做了些机器进建的一些尝试,比如道基于GAN算法的现实世界生成,或者是地表地形的风格化迁移等。还有一个很常见的问题是正在用Houdini做这些工作的时候,数据的导入导出和计算都需求非常长的等待,有些团队会倾向于正在引擎中本人实现生成算法,我们正在这方面也做了一些简单的尝试,参考了《地平线:零之曙光》(Horizon Zero Dawn)的做法,使用GPU加快的方式做地表地形的生成和植被的分布。
过程化内容生成的技术除了使用正在逛戏开发中,还有其他使用场景。例如NExT跟新华社合作的数字航天员小诤的火星视频中,我们使用了过程化内容生成的技术模仿火星的地貌。UE5的Nanite能够正在不限制三角形数量的情况下做大量的几何细节,这该当也是后续逛戏制作的趋势之一。