浅谈游戏中非重要点光源的合并

作者:Rushot
2023-09-23
5 2 2

前情回顾

游戏中的光源数量是决定游戏性能开销的一大重点,很多时候甚至是最大项。但在某些游戏情境中,我们又不得不较长时间地使用多个光源,这就造成了非常尴尬、被动的局面......

笔者花费大概 20 天,思考并解决了这个问题。顺道写下这篇日志,留给那些还不想秃头的人 。


先来回顾一下游戏项目的开发进度,已知可以略过。

目前,已经部署了包括伯耐利 M4 和 AA-12 等自动霰弹枪,其射速非常快。选用爱发电上的 Banner 图展示一下 AA-12:

按照常识讲,照明枪的照明弹应该是 14G 左右口径(霰弹枪铅径),但由于游戏设计,我们选择跟攻击性霰弹枪一起,使用 12G 口径,目的是整体提升霰弹枪种的应用范围和适用性。

一顿操作猛如虎之后,开始制作照明弹效果,马上就遇到了巨大的问题。

0. 问题的出现

照明弹光照存在以下特点:

  1. 相对于主光照优先级低,但必不可少;
  2. 同屏存在数量可能巨大;
  3. 照射范围略大甚至巨大;
  4. 需要阴影或部分需要阴影;
  5. 与粒子系统伴随出现。

其中第 2、3 点最为致命。

按照常理,玩家通常只需要射出 1-2 发照明弹,提供场地照明即可。但是本着程序设计人员必须把用户想象成“猴子”的经典理论,可以预见,总免不了有特殊癖好的玩家存在,闲来对着天空射烟花。

然后,你总不能告诉玩家说,5 秒内只能发射一次......吧(板砖警告)?

可是,若要设法满足玩家,则会发生以下交通事故:

完全无优化的效果,FPS 直降到 30 左右,才 9 发照明弹而已

本着多想想就会头秃,再想多几天就会“原地去世”的觉悟,赶紧询问了一下小伙伴们:

随即惊喜地发现,这好像是个业界天花板级别的技术问题,我去......

结果很明显:大范围大剂量点光源似乎就没在几个 3A 级游戏里被开放式地允许过,这就是天花板的感觉。但项目已经做了,照明弹通用 12G 霰弹的口径也已经确定,双持 AA-12、美妙的十几发/秒射速连喷摆在那里......只能霸王被弓硬上。

以下是主要技术节点的尝试与结论演示。

1. 光的合并

在我开发的游戏中,爆炸会对小型植物产生烧炙火焰。由于小型火焰也带无阴影光照,所以同样属于额外的非重要点光源,可以跟照明弹问题并列处理,使用同一个优化脚本。

首先,我们看看单纯多个无阴影光照的开销。

如果把多个无阴影光照合并,会发生:

显然,经脚本优化后,帧率(FPS)有明显优势,而优化脚本的开销可以忽略。

也就是说,就算我们不使用阴影,两位数以上的光斑对游戏性能的开销也非常可观(这是 Deferred,如果是 Forward,基本可以自行了断了)。

不过问题还很多,因为当光灭失时,光斑会产生抽搐感或强烈抖动,于是,我们取所有合并光的平均位置。但由于光到耗尽时会有渐变暗和灭失,所以还是存在小抖动和不自然。

这里面就涉及一丁点开销问题。我们按两个光之间的强弱比例使用 Lerp 线性插值求得整体加权平均位置,效果非常爽滑:

2. 阴影控制

由于阴影开销巨大,程序员都会下意识把它们关掉,而这就产生了一个尴尬问题。

比如说,你在房间外面发射了一颗照明弹,房间外面是亮的,房间里面是暗的(正常)。然后另一个玩家(猴子)出现,向你射了十几发过来,结果由于阴影限制,后面的无阴影光照直接就把房间里给照亮了。

所以思索再三,我们最终做出限制:距离镜头最近的前 n 个光照允许阴影。

不过,如果直接把镜头位置跟点光源中心位置比较,似乎会产生不合理现象。毕竟光源是有范围的,它的阴影产生也会有一个范围,但我们的锥形视界明显靠前。所以,具体算法参见下图:

我们为镜头选择一个 Check Point。位置大概是镜头正前方 0.3-0.5 光照 Range 的位置。因为按照 Unity 里光照的实际操作经验和现实世界的光理论,光在超过一半 Range 之后,其光强衰减和距离起码是三次方关系,也就是 1/8,12.5%。所以,我们默认在这个范围外的阴影及其强度不予优先考虑。那么与镜头距离的判断基点就是 Check Point,而非 Camera.position。

此外,基于前面的第 1 节,我们已经将光进行合并,所以只需要在合并后活跃的光照上进行这项判断。

最终效果和 FPS 如下,照明弹数量超过 15 发。

最终效果的配置参数:

  • 允许 n=2 个阴影光照
  • 光射程 10% 范围内合并

事实上,我把燃烧时间改到 50s,直接对着天空将一盒照明弹(50 梭子)全发射出去,FPS 也是差不多这样,保持在 50 上下,纹丝不动。

秃头了这么多天,感觉还是值得的,我先去植一下发(笑)。

3. 其它可能存在的问题

1. 当然,这种优化逻辑在比较窄或者复杂的地形和建筑内,绝对还是有穿帮的可能,但在那种环境下使用照明弹,基本不是常规思路(猴子),可以拉出去直接击毙。

2. 另外,关于光合并,会涉及一个合并后光强度的取值问题。由于我不想翻阅厚如字典般的 Unity 光照内核资料,加上我到现在还用着 5.6 版本,如果研究半天,新版发生变化岂不是白给了——所以直接肉测了几个场景,取以下代码逻辑:

combineIntensity  = intensityMax + (intensitySum-intensityMax>1f?  Mathf.Sqrt(intensitySum-intensityMax) : intensitySum-intensityMax);

*注释:intensityMax = 合并群组里的最大光强;intensitySum = 光强总和

本文为用户投稿,不代表 indienova 观点。

近期点赞的会员

 分享这篇文章

Rushot 

创造的快乐高于一切 

您可能还会对这些文章感兴趣

参与此文章的讨论

  1. Su Qing 2023-12-22

    太专业了。要是我来,我想想,火焰直接发光贴图,照明弹给cd,携带上限减少。照明弹直接特效都不给,就一个无阴影光源,抽象化表示区域变亮。笑,你就说解没解决吧

    • Rushot 2024-01-01

      @Su Qing:前方差评如潮警告(笑)

您需要登录或者注册后才能发表评论

登录/注册