本文首发知乎:https://zhuanlan.zhihu.com/p/459639904
2017年至2019年,我们一个几人的小团队开发了独立游戏《安妮》。如今时隔两年,再回顾一下这段职业生涯中最开心也最痛苦的经历,大量教训,希望能对后来的独立游戏开发者有所帮助。所有内容大概会写三篇,本篇是第一篇,先聊聊技术。
一、源起
这个项目的起源,是我把magicavoxel做的体素模型导入到引擎里,做了个破碎的效果,当时的截图:
公司的美术大佬看到后觉得有点意思,那时正好想做个小项目,于是就定了做一个体素风格的小游戏。高精度体素模型会有一种玩具感,配合俯视角更显精致。(当时知乎上有个学生团队在做体素游戏,也写过关于画风的讨论)
《Monsterologist》 开发日志3 体素美术心得
https://zhuanlan.zhihu.com/p/25195200
推特上体素artist的作品
定了俯视角,再考虑利用上模型破碎的效果,以及团队规模和能力,我们确定了做一个俯视角射击(top-down shooter)的PC单机游戏。第一版战斗Demo完成后,我认为单纯射击卖点不足,考虑steam玩家特性,做一个走心的剧情故事会很加分,这就有了后来《安妮》的样子了。同时,这个剧情也为后续开发挖了大坑。
(后来的后来,主打体素破碎的独立游戏《Teardown》上线并大卖,让我感慨万千。《安妮》的立项就带着美术主导的基因,自然不会走这种新技术、新体验的方向。但作为一个典型的产品型程序员,把技术用于创新体验,真是一个美妙又奢侈的追求。)
体素沙盒破坏游戏《Teardown》
美术风格有大佬把控,我的任务就是搭建一套基于magicavoxel的资产管线,在极其有限的人力限制下把游戏做出来。所以,技术的重心肯定要放在加速创作(Asset Pipeline)和玩法实现(Gameplay)上。
我们使用的引擎是unity 5.6,中期为了用Timeline做过场动画,升级到了unity 2018。我们前面很长一段时间只有4个人,2程序+2美术,没有能力去做渲染管线的定制。我们直接使用引擎内建的延迟管线,使用引擎标准的PBR材质,使用unity官方的PostProcessingStack(再加一个特制的后处理勾边)。因为场景大部分物件可破坏,所以没有烘lightmap(也就省了模型2UV的工作量),GI的效果就靠后处理的SSAO、SSR。以及,游戏画风偏风格化,美术打了很多氛围光,对间接光的缺失也不太敏感。
《安妮》实际游戏截图
二、体素模型管线
我们的体素模型都是使用magicavoxel 0.98.2版本制作的,如今这个软件在独立游戏圈基本上是无人不知了。记得18年参加GGJ时就看到很多组用magicavoxel来做资源。体素模型在引擎中的渲染还是会走传统光栅化的方法,但具体的方案就会有很多选择,比如体素生成完整mesh、geometry shader/compute shader生成顶点、instancing绘制cube等等。我们的游戏不需要像沙盒游戏那样可编辑,就使用离线生成mesh的方法。
magicavoxel原本支持导出obj模型,但会有一些问题,比如会丢失材质信息,再比如贴图只使用一个256色调色盘,导致无法高效的合面。我们自己实现了一套vox模型导入,解决上述问题,同时保存了体素原始数据,用于模型破碎的粒子效果。
生成mesh的算法,就是从voxel提取可见的quad,然后合并quad,再用两个三角形填充quad。合并quad使用贪心算法,参考的这篇文章:
Meshing in a Minecraft Game
https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/
合并quad后,就可以对所有quad装箱,给顶点生成UV。进而把voxel的颜色和材质信息填到两张贴图,一张保存RGB颜色,一张保存Metallic、Roughness、Emissive。贴图通常128,甚至64就够了。材质里都使用Point采样。
其实,简单地从一个quad生成两个三角面,会有面断开的问题,但因为这些模型都不会做蒙皮动画,所以不会出现破绽。要解决的话,需要用到Delaunay三角化,模型面数也会增加一些。
体素模型生成的mesh
静态模型解决后,再考虑角色的问题。
因为我们没有专业的动画师,所以想尽量使用网上的动作资源(开始觉得很艰苦,后来知道《绝地求生》都用了大量虚幻商店的资源……)。unity支持人形骨骼的动作retargeting,我们只要做好骨骼就好了。骨骼也可以自动生成,只需要在模型上标出这是人体的哪个部位,就能算出人体关节的位置。当时的magicavoxel版本还不支持创建模型结构,我们就用自己的土方法:把模型复制一份,给身体不同部位染不同的颜色,这个新模型叫rig模型。编辑器生成角色mesh时同时读取这个rig文件,就同时生成了一份人型骨骼。另外还同时自动生成了角色布娃娃,死亡时激活使用。
右侧为rig模型
用网上的动作测试一下,效果还行。
自动生成骨骼,使用引擎动作重定向
有了这套流程,我们建模的成本极大地降低。正常项目做一个角色几周的流程现在只需要几小时,对于不太重要的npc角色,美术大佬可以一天干出十几个。
模型和动作搞定了,特效也直接使用商店的资源,四人团队就这么启动了。
(现在回头来看,没有动画师和特效师是个错误,严重限制了怪物、关卡的设计以及设计意图的传达。项目尾期动画特效同学加入后才顺利了很多,免费的才是最贵的…… 所以,我当时解决问题的思维方式还是工匠而不是领导。)
三、体素破坏效果
在游戏中把一个模型破坏掉是个复杂的技术,涉及到一堆看不懂的数学方法,所以破坏早已集成到各种物理引擎中。要做运行时生成的破坏更是复杂,可以参见《彩虹六号》程序大佬的这篇血泪史:
《彩虹六号 围攻》中的破坏系统是通过怎样的引擎实现的?
https://www.zhihu.com/question/49317501/answer/124322645
但是,对体素模型做破坏就非常简单了。根据破坏的位置对体素生成voronoi划分,然后再重新生成碎片mesh。和破坏网格模型相比简直就是玩具车和F1的差别。我猜《Teardown》的破坏也是这么实现的。
《安妮》中的实现则更简化。前面提到,我们模型的生成是离线进行的,所以碎片也是离线纯手工编辑的。因为自动生成难以识别出模型的材质特征。比如击中窗户玻璃时希望玻璃破掉,而不是玻璃带着周围的窗框一起破掉。我们使用和角色骨骼类似的方法,为每个可破坏模型再制作一个part模型,使用不同颜色表示不同的碎片。同时也表示了这一片的物理属性,最终影响到击中后的特效音效,破坏后是碎成碎片还是直接碎成粒子,以及生成碎片的质量和摩擦系数。
右侧为part模型
体素的破坏算法虽然简单了,但破坏的逻辑规则还得是完整的:
每一种攻击都要带有一个“破坏等级“属性,每一个物件对应的有一个”抗破坏等级“。比如徒手攻击可以破坏玻璃,但打不烂木板,枪支可以破坏木板但打不烂水泥掩体,Boss的特殊攻击可以破坏掩体,这样就和玩法结合了起来。
碎片也会根据物理材质有不同抗破坏的等级,主角的枪可以把木箱打成碎片,Boss的攻击可以把碎片砸成粒子。
每个物件也会有自己的生命值,被击中时只是对应部位破坏变成碎片,当生命值降为0才会整体都破坏掉。
所有游戏的破坏规则都是大同小异,因为都是在一定的技术限制下模拟现实。工业化流程下的做法可以学学《Control》的这篇GDC分享:
[gdc20]control的可破坏环境技术
https://zhuanlan.zhihu.com/p/380580194
四、Gameplay
《安妮》的Gameplay开发占了程序的绝大部分工作量,但值得拿出来说的并不多。现在想想,稍微有趣的几个点:
我们做了一个弓箭点哪射哪的功能,就是解了个抛物线方程,根据位置、初速度和g值算出发射角度。但这个功能意义不大,因为游戏一定要支持手柄操作,而手柄玩俯视角射击时不能精确选择目标点,所以也就没法利用这个功能做玩法。
有一些关卡,是依赖物理的,比如滚木落下来把桥砸断。这些滚木开始都是物理驱动的,运动和碰撞都比较自然,但是会不稳定,严重时会卡住流程。如果手调下落动画,又做不到这么自然。于是我们做了一个录制轨迹的功能,提前用物理驱动多跑几次,选择最好的轨迹,做成关键帧动画。
敌人追击时分散开移动,靠近主角后自动包围。这也是很多丧尸类AI都有的,避免玩家放风筝优势太大。用的方法就是移动时增加单位间的排斥力,靠近包围时由目标单位身上的位置管理器统一分配站位。
在成本有限的独立游戏中做高技术难度的挑战并不理智。就《安妮》而言,我大部分精力转到策划以后,就只有一个程序人力,要做所有怪物、Boss、UI系统,维护剧情编辑工具等等,这个同学还设计了几个Boss……
所以,独立游戏对程序员的要求是广度大于深度,且要有产品思维,这和大厂的要求是相反的。
五、体素的展望
体素在《安妮》中仅仅作为一种美术风格和对应的资产管线。实际上,如果整个游戏基于体素构建,利用好体素数据结构的整齐性,能做的有趣的事情非常多,脑洞几个:
真正的全场景程序化破坏,和玩法结合。上面提到的《Teardown》还是把破坏当作一种模拟体验,《彩虹六号》则是把破坏和玩法结合了起来。我心中的一个把全场景破坏和玩法结合的非常棒的游戏是《Broforce》。
基于体素的实时GI。体素适合光线追踪,可以尝试一下当前硬件在纯体素场景中,做光栅化+光线追踪混合渲染能达到什么效果,可否实现高效的实时GI,就像简化版的VXGI。(知乎大佬的相关实现:https://zhuanlan.zhihu.com/p/120361846)
体素的高精度大世界。利用GPU driven可以大量剔除不可见面,体素模型的LOD生成是否可以更灵活,这些都做完善的话就是一个体素版Nanite。
基于体素的PGC(程序化内容生成)。3A项目中,PGC通常用于大型开放世界的内容填充,为的是降低人力成本,使用的算法和工具都极其复杂。而独立游戏中,程序化生成是和玩法结合起来的,为的是随机性和重玩价值。体素下PGC可以简化很多,经典案例就是《我的世界》中的地图生成。
关于体素的特点和优势,可以看Milo大神早年这篇:
以体素建构三维游戏世界
https://zhuanlan.zhihu.com/p/20065737
以及知乎上近期这篇:
体素引擎,来自元宇宙的基本问题
https://zhuanlan.zhihu.com/p/452600325
当然,做独立游戏,技术还是要为产品服务的,游戏最终的竞争力还是靠产品体验,不能本末倒置。《安妮》这个项目中我也做了大量(不专业的)策划工作,下篇接着聊。
原文:https://zhuanlan.zhihu.com/p/459639904