抓手
标题起得很唬人,但一点不唬人。
作者在这里告诫大家,不要使用Cascade的对象池,会有bug,并且不起作用!
建议大家都转成使用Niagara,Niagara的对象池功能齐全,并且没什么bug。
后面会具体说明原因。
同时本文会告诉大家大家具体的使用方法,以及什么情况下需要使用对象池。
本文将基于UE4.26.2的源码进行分析研究。
UE4粒子对象池的大坑
Cascade和Niagara的对象池代码原理几乎一致,但是感觉是两个人写的。(而且是负责Niagara的同学复制Cascade的对象池代码来改改)
所以Niagara有一定的优化,Cascade有坑。
具体的坑,有五个:
1、Cascade的对象池没有初始化多少个实例的功能,虽然Cascade的UI上看起来可以设置,但却没有实际功能!而Niagara是有该功能的。
原因是ParticleSystem类和NiagaraSystem类都继承了父类UFXSystemAsset,都有
uint32 PoolPrimeSize = 0; 这个变量。但ParticleSystem却没有实现相应的功能。反而NiagaraSystem在Postload方法里调用了 PostLoadPrimePools方法去做这件事。
2、从Cascade的对象池里取出的实例会重新Register Component。而Niagara则默认不重复register。这样导致Cascade粒子从对象池取出来,照样会浪费CPU的消耗,而且消耗还不低。
在我的机子11代i7 CPU上,regiseter一次Component居然需要花费2ms左右,怎么可能不卡?
而Niagara的优化:
Niagara还注释了为了避免Register/Unregister Component的消耗:
3、即便从Cascade的对象池取出的实例,attach到某个component上仍然调用的是SetupAttachment方法,而不是AttachToCompoent方法。但SetupComponent是构造函数里调用才生效的,所以从Cascade对象池取出的无法正确attach到component上!
4、调用SpawnEmitterAtLocation方法去Spawn粒子,从Cascade的对象池取出的实例无法正确设置它的transform!因为它调用的是SetRelativeLocation_Direct和SetRelativeRotation_Direct,该方法只能在初始化的时候调用才能起效,因此Niagara改成了SetWorldLocationAndRotation,该方法会后续用tick update的办法去更新位置和rotation。
5、Niagara有个小坑,就是AnimNotify_PlayNiagaraEffect是不开启对象池的,如果不想改引擎代码,就只能重载该方法才能使用了。同理,Cascade的AnimNotify_PlayParticleEffect也是。
Cascade的对象池源码在:
UGameplayStatics.cpp和WorldPSCPool.cpp
Niagara的对象池源码在:
NiagaraFunctionLibrary.cpp和NiagaracomponentPool.cpp
如果细看的话,这两份代码不能说是毫无关系,只能说逻辑几乎一模一样。
如果想用Cascade的对象池,建议按照Niagara的做法把Cascade的bug给修了。具体查看上面的每个对比的点。
具体使用方法(仅介绍Niagara)
初始化对象池:
打开NiagaraSystem,选择System,然后在Selection面板的System Properties ,Performance里的Pool Prime Size,填入大于0的数字:
但Pool Prime Size大于Max Pool Size,它也只会按Max Pool Size的数量来初始化,所以可以适当调整Max Pool Size数量大于或等于Pool Prime Size数量。
调用代码去Spawn时:
UNiagaraFunctionLibrary::SpawnSystemAttached或SpawnSystemAtLocation方法,在参数里传入ENCPoolMethod::AutoRelease或者ManualRelease才能使用对象池。
- AutoRelease:在lifetime到时间后自动放回池子里。
- ManualRelease:意味着后续需要你自己手动调用ReleaseToPool方法才能把特效放回池子里。
蓝图里Spawn:
Pooling Method选择AutoRelease或者ManualRelease。
为什么需要使用对象池
因为UE的粒子在Spawn的时候,ActorComponent需要注册Component,这个时候就会对CPU产生比较大的消耗。
而使用对象池的优化原理就是,先初始化一定数量的实例在池子里,然后需要的时候再去池子里取,然后在激活使用。
什么时候需要使用对象池呢?就是同一种粒子特效需要高频播放的时候,或者同时大量播放的时候,那么对象池是对于CPU消耗来说,是个必备良药。代价只是多占了那么点内存嘛,初始化加载时间会多一点点嘛(只要数量不会太夸张,用到成千上万的数量)。
总结:
对于一个这么大的引擎来说,有这样的bug的确是让人意料之外,但UE也希望大家都使用Niagara,Cascade也在被慢慢遗弃,截止到4.27,Cascade对象池的问题依然存在。而UE5则默认是关闭Cascade的。
所以本文作者在这里也呼吁大家都直接转为使用Niagara,虽然4.26的Niagara确实还有一些不好用的bug,但如果熟悉了,也是能避免的。并且Niagara更自由了。如果完全不使用对象池,则继续使用Cascade粒子是没问题的。文章来源:https://www.toymoban.com/news/detail-459372.html
参考:
Unreal引擎4.26.2源码。文章来源地址https://www.toymoban.com/news/detail-459372.html
到了这里,关于深谈UE4粒子系统对象池的惊人大坑的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!