在这篇客座博文里, Whiteboard Games 详细介绍了工作室首款商业作品 《I See Red》(血海雷霆) 的历史,以及游戏独特配色背后的技术思考。
我们是Whiteboard Games,在2021年成立于阿根廷布宜诺斯艾利斯,由五名希望在游戏行业开辟道路的大学毕业生组成。从那时起Whiteboard已经成长为包含30名年轻从业者的团队,而本次我们大家聚在了一起来讨论我们首款商业作品:《I See Red》。
《I See Red》是一款双摇杆轻度rogue射击游戏,它充斥着愤怒、枪战、复仇、血腥、悲惨经历,还有名字里的“殷红”。它科幻的环境、俯视的镜头,以及独特的美学:除了黑、白、灰和红外几乎没有其他颜色,使之轻易从其他游戏中脱颖而出。这种美术风格确立于开发早期,与剧情和游戏流程紧密相连。当然,这也带来了一些挑战:不是所有人都能制作(或爱玩)这种颜色如此有限的游戏。那我们究竟是怎么做到的呢?请在下文一探究竟。

《I See Red》诞生史

我们先简单回顾下过去,看看《I See Red》变成今天这样的外观演变和关键决定。

首个原型

这一切都开始于布宜诺斯艾利斯Da Vinci First School of Multimedia Art的“电子游戏设计与编程”论文项目。诞生自该论文的游戏在美术上的要求更低,因为学生们根本就没什么资金。此时,红色还不是游戏的主色。游戏里有蓝色甚至绿色,但这些颜色不久后就被去掉了。
图注:《I See Red》在2020年4月的第一个版本

职业开发

课程结束后,我们的创始团队并没有抛弃项目,而是看到了它的商业潜力。我们决定在校外组建一支团队继续开发,并最终成立了Whiteboard Games工作室。(有趣的是,学校的几位教授也看到了项目的潜力,我们在请求帮忙时,他们也决定加入团队。)
到这里,基本的游戏已经确定:它应是一款关于血红、暴怒和复仇的快节奏科幻射击游戏。
图注:在2021年3月开启职业开发时的《I See Red》

最终外观(使用HDRP)

之后又过了几个月甚至几年,经过与多家发行商和投资商的交谈,我们给《I See Red》加了许多相互连通的关卡,敌人现在不仅有人类,还有外星人,另外还有大量的被动物品、过场动画和更为精良的美术风格。经过一系列的bug修复、测试,内容与 性能改进 ( 不用谢 ),游戏终于准备好上市了。
图注:2022年2月HDRP下的《I See Red》最终版外观

最终外观(使用URP)

终于到了发布游戏演示的时候了。我们对自己的作品很有信心,并参加了几场线下活动和竞赛。在这个阶段,我们计划把游戏发布到主机,从HDRP转移到URP,用清晰的HD画面换取更为风格化的美学。我们还给灰度颜色增添了一股冷色调(悄悄说一句,蓝色其实又回来了),来营造更强的金属感,还继续打磨了其他东西。这种转换使我们不得不在URP里逆向工程并重现部分HDRP功能,不过结果非常值得。
除了先前的外星人关卡外,《I See Red》现在还有敌对机器人、几名首领、故事线、QA、本地化以及更多“做完的工作”。是时候开启前进的绿灯了。
图注:《I See Red》在2022年10月发布时的最终版URP外星人外观
这场漫长的旅程遍布着挑战和改变,另外还有数年的辛勤工作。我们认为它的观感非常棒。最终,我们把游戏做完并发布了。不过它究竟是怎么做的呢?技术美术粉丝们的福音来了:接下来讲的是技术细节。
(预警:我们全力做出了好多种血的效果)

血液VFX

我们在血液上花了很多时间,它是玩家击中敌人或被击中时的主要视觉反馈。这种元素需要足够清晰、令人满意,红色也是游戏最重要的颜色,所以容不得半点马虎。
既然想用血把世界染红,灰色的环境与血液之间就必须有强烈的对比,环境内还得有不同样式的贴花。我们本想用纹理来遮盖贴花,但数量太多时贴花会显得重复。这一点是我们想避免的。
我们最后想出的方法组合了图像噪点、URP贴花投射器和世界坐标,根据贴花所在位置的不同,它的形状也会变化。使用这种技术,血液的宽度、高度、边缘平滑度和粗糙度都能改变,并且还带有流畅的动画。我们可以很方便地在倒地的敌人身下生成一滩血泊。
图注:生成《I See Red》贴花的Shader Graph
通过改变albedo的颜色和噪点遮罩的属性,我们可以给外星人和机器人生成不同类型的血,后者其实更像是机油。这并不仅仅是为了在美学上区分不同的敌人,区别不同的血液在游戏玩法上也同样重要。玩家有一项被动技能可以“吸收”残留的血液,来获得不同的效果:人血没有特殊效果,外星人血造成伤害,机器人血有治疗效果。
图注:浓稠又恶心的外星人血同样带有流畅的动画
除了贴花之外,《I See Red》还用到了许多血液粒子。就比如刚刚提到的被动技能:我们需要用某种方式告诉玩家吸收完成。结果就做出了一种迷你的血液旋风:
图注:三种血液“旋风”粒子,对应外星人、人类和机器人三种敌人。
这些小旋风使用了一张滚动纹理和一个粒子效果实现。这个粒子效果是一个3D建模而成的缎带(一条多边形组成的条带),它附带的着色器会使用主UV一直向上滚动纹理。这样一来,我们就能用粒子系统上的自定义数据来修改网格的速度、流动方向和形状,并加上淡入淡出的效果让条带能流畅地出现在旋风的顶部和底部。在此之上再加些额外的血丝,一股把血液吸收进玩家的反向血液旋风就做好了。
说到粒子,就不得不提玩家和敌人在受伤时的命中粒子效果了。这些粒子效果会与前边的血泊/贴花在同一帧上生成,两者都借助了代码里的协程播放动画、无缝地完成衔接。它们生成的方向是子弹的前进方向,一般都与玩家的方向相对。
用代码编写便于个性化效果,伤害更大、敌人更近、或者效果更靠近墙壁时粒子也能更大。我们用射线来确定贴花的长度、粒子穿过墙壁的距离,以及贴花可能的形状(如果需要投射到墙壁上)。把这些值传到动画里,神奇的事就发生了。
图注:命中效果能让子弹射击更让人满足

命中效果代码段

    
    
public void Being . DropBlood ( Vector3 hitPoint , Vector3 hitDirection , float sizeNormalized ) // 这会在一只生物(“Being”)受到伤害时被调用。 { int randomBloodParticleIndex = Random . Range ( 0 , bloodParticles . Length ) ; // 每只“存在”都有包含所有血液效果作为子对象,命中时一个随机血液效果会被选中。 bloodParticles [ randomBloodParticleIndex ] . transform . forward = hitDirection ; // 我们让血液效果面朝子弹或冲击的前进方向。 if ( Physics . Raycast ( bloodParticles [ randomBloodParticleIndex ] . transform . position , hitDirection , out RaycastHit hitInfo , maxBloodParticlePossibleSizeDistance , obstacleMask , QueryTriggerInteraction . Ignore ) ) { sizeNormalized = hitInfo . distance / maxBloodParticlePossibleSizeDistance ; // 我们用Raycast试着在血液生成的方向上搜寻墙壁等障碍。 // 如果真的找到了, // 为避免穿过障碍,我们会根据障碍的距离来缩短效果。 } else { sizeNormalized = Mathf . Clamp01 ( hitDamage / ( maxHealth * maxDamagePercentageForMaxBloodParticleSize ) ) ; // 否则,我们根据该“存在”所受伤害占总血量的比例来设定血液效果的大小。 } bloodParticles [ randomBloodParticleIndex ] . Play ( sizeNormalized ) ; } public void BloodParticle . Play ( float sizeNormalized ) { bloodParticleSystem . transform . localScale = Vector3 . Lerp ( startingScale * minSizeInPercentage , startingScale , sizeNormalized ) ; bloodParticleSystem . Play ( ) ; // 最后,我们将血液粒子的大小设在最大值和最小值之间,再播放效果! }
这血可真不少,一片红色。由于游戏色板有限,我们得尽力不损失游戏任意方面的可行性。维持这种标志性的画风意味着我们得用上很多工具和技巧、发挥创意。比方说,红色的东西不一定得是红色。
你可能会看到一扇红色发光的门,在穿过去后它会变成灰色。敌人也是一样的,他们在有敌意时为红色,在敌意“消失”后就变成灰色。借助这些图像信号,游戏用独特的颜色来提示哪些是应该关注的东西:比如未探索区域、重要物品、危险障碍等等。这就好像玩家一直开着“侦探视觉”,只能看到当时最需要注意的东西。
但如果玩家不能像我们这样看到红色呢?如果《I See Red》的玩家没法区分红色和灰色的不同呢?我们当然希望每个人都能体验这场“暴怒”,这也是游戏支持13种语言的原因。我们肯定这13种语言的使用者总有会用得到无障碍功能的地方,于是我们有了自制的URP色盲模式。

URP特殊色盲模式

在制作《I See Red》时,我们就知道不是每个人都能感知这个黑色、白色和红色的宇宙,所以我们实施了不同的色盲模式,让每个人都能尽情游戏。
该功能最好的制作方式是用Unity的Scriptable Render(可编程渲染)功能和一个简单的着色器。其背后的主要想法是用SRF里的对照表(Look-Up Table)转化各通道上的数值,再将转译后的值传给着色器用于最终的渲染通道。由于效果需要作为最后一条通道覆盖到每个渲染对象上,这条通道会在UI渲染结束后执行,也是游戏每一帧的最后通道。
我们调查了不同类型的色盲症,理解了每种色盲患者怎样感知颜色,用Scriptable Render照顾了他们的需要,并设立了对应的模式来锐化或修改颜色:Protanomaly对应红绿色盲,Deuteranomaly对应绿色盲,Tritanomaly对应蓝黄色盲。不同的患者所看到的“红色”可能不再是红色,不过这也OK:到最后,最重要的还是让所有人都能享受游戏。游戏里还有更多系统来传达所有的愤怒。
图注:《I See Red》里的多种色盲模式
终于,所有人都能欣赏我们血液的美……当然,你得超过当地的法定年龄。血液不是《I See Red》美学的一切,除了有各式各样的红色,灰色也十分重要。

Splatmap着色器

我们希望让颜色方案能适配到新的模型上,不必再从头做一遍纹理,这花了不少时间。到这里我们得澄清下:《I See Red》的颜色其实不是黑、白、红,而是红、绿、蓝,和其他游戏一样。开头我们撒了个谎,但游戏的外观还是不同于其他游戏的。我们在一个自定义着色器使用了Splatmap,它会用每张纹理上的不同通道(红、绿、蓝或alpha)把多张纹理或遮罩组合成一张。
图注:建模流程的不同阶段,包括RGB Splatmap的制作
这下我们能在引擎里分别控制每个通道的数值,更好地控制游戏内的颜色,加载更少的纹理来节省更多系统资源。这对缩短迭代时间也有巨大的帮助。
图注:Unity Editor中的Splatmap

还有更多东西?

血有了,敌人有了,环境有了,颜色也有了,游戏看起来很不错。接下来,我们还能聊聊自定义雾气、光照和摄像机上的数学、色调映射,还有过场动画里的超酷伪视角……
是的,有很多东西能讲,不过这得花上好几小时(写这篇博文也花了不少时间),所以不如现在就打住。不讲技术了,直接去体验吧:自己去玩玩《I See Red》,去发现我们这里所讲到的东西。最后,要是你想要了解更多,请立即 联系我们 或Unity。
《I See Red》目前已在 Steam 开售。感谢阅读,下次再见!
Logo

分享前沿Unity技术干货和开发经验,精彩的Unity活动和社区相关信息

更多推荐