-
Notifications
You must be signed in to change notification settings - Fork 395
Effect
特效可以大大增强游戏的画面感染力。特效最重要的组成部分是粒子系统。由于粒子数量非常巨大,处于性能原因,通常游戏引擎不会把每一片粒子都当成一个 Scene 场景对象对待。几乎在所有的游戏引擎中,粒子系统都是单独实现部分。游戏引擎管理的是粒子发射器,它是一个场景对象;当发射器发射出粒子后,发射物就按一定规则自生自灭。
粒子系统非常重要,性能敏感,Ant 引擎在开发时曾经实现过一套例子系统。随着游戏开发,我们发现,实现一个功能齐备、性能高效的粒子系统并不难,但制作一个好用的编辑器有巨大的工作量。而美术创作人员制作出来的效果好坏,受编辑器的影响更大。
特效也不仅仅只有粒子系统。
经过一番调研,我们决定集成 Effekseer 。虽然有一些看起来更好的中间件,但多半是商业化的。作为一个采用 MIT 开源许可证的引擎项目,同样采用 MIT 许可证的 Effekseer 是目前的最佳选择。
我们为 effekseer 开发了 bgfx 的 binding ,让它可以用于我们的引擎。除了自定义材质这个特性外,其它特性全部支持了。在我们的游戏开发过程中,完全满足了游戏的需要。
在对我们的游戏做性能测试时,我们发现过多的特效会占用大量 cpu ,这会降低游戏的帧率。幸运的是,对游戏引擎来说,管理的是粒子发射器的空间状态,粒子本身是引擎其它部分不必关心的。只要我们合理的安排 pipeline ,尽早计算出粒子发射器的位置,接下来的计算都可以和其它业务并行。
而 bgfx 提供了良好的多线程支持,可以在不同线程平行提交图形指令。所以,我们非常轻松的把特效模块整个移入了独立的 ltask 服务中。改为独立线程处理特效后,提高了游戏帧率。但需要小心,这只是降低了每个渲染帧的延迟,对手机设备的电能消耗并没有减少。所以在实际使用时,还是需要避免使用太多的粒子发射器。
独立服务还可以帮助我们将特效和其它部分隔离开,所以,一旦帧率不够或是能耗太大,可以通过这个服务直接关闭特效模块。一般都不会对游戏逻辑造成影响,只是画面效果受损。
使用特效并不关心特效服务的存在。导入 ECS ant.efk
这个特性即可。
world:create_entity {
policy = {
"ant.scene|scene_object",
"ant.efk|efk",
},
data = {
scene = {},
efk = {
path = "/pkg/ant.test.features/assets/efk/miner_efk/miner_dust.efk",
},
visible_state = "main_queue",
}
}
创建一个带有 "ant.efk|efk" policy 的 entity 就可以得到一个特效对象,它同时必须是一个 Scene 场景对象,即需要 ant.scene|scene_object
这个 prolicy 。特效对象必须引用 .efk 文件。.efk 文件是用 Effekseer 编辑器制作出来的。
一般我们不会直接在代码中使用 create_entity
创建特效对象,而是使用引擎编辑器制作 Prefab 在编辑器中,可以给预制件添加特效,并为特效加入时间线(参见 Animation)
如果不想通过时间线触发特效,使用 :
local iefk = ecs.require "ant.efk|efk"
这个 iefk 中的接口也能独立控制特效的播放过程。
在介绍 挂钩 时我们提到过:如果多个挂钩应用了同一组 entity ,那么,这组 entity 会被绘制多次。引用相同 entity 的 hitch 画面表现应该是完全一致的,仅仅位置不同。这同样也适用于特效。
例如,在我们开发的游戏中,场景中有大量冒着烟的相同建筑。建筑是相同的模型,而烟雾使用特效制作。我们就使用了 hitch 来优化这种场景。引擎可以通过 hitch 了解到哪些对象在渲染过程能够合并。
注:在实现时,因为 effekseer 并不支持将一个发射器渲染多次,所以 Ant 引擎实际上创建了多个特效示例。由于一些实现上的限制,它们并不会保证严格的一致。好在大多数情况下,我们也不需要严格一致性。我们还可以通过参数,将特效对象配置为即使被多个 hitch 引用,它们也是分别独立的粒子发射器。