昨天偶然发现了XNA粒子系统的一个神器——Mercury Particle Engine 3.1 for XNA 4.0 (Binaries)。拿到这个引擎用了一下,第一感觉就是我这个在团队中负责做特效的可以被撤职了,而且是自己把自己撤了!因为Mercury粒子引擎做的实在是太好太漂亮,而且引用也方便。下面是这个引擎“光束”特效的一个截图
怎么样?看到之后颤抖吧!我仰天长叹,国内的程序员都死哪了?!怎么都是国外的在做这种引擎,而且虽然不是开源,不过用反编译工具是很轻易的窥视作者的代码的。
感叹完了,今天又把这个系统研究了一番,并且反编译了一下看了下源码发现其实是我写粒子效果的思路出了问题,其实Mercury引擎的算法基础是很简单的。
粒子引擎通用的算法机制
Speed += Acceleration;
Position += Speed;
Rotation += AngularSpeed;
Color = F(gametime);
Scale = F(gametime);
当然在Mercury引擎中又针对加速度多了一个方程。我觉得并不是十分必要,因为从物理角度来说Force跟Acceleration其实是靠质量mass来连接,而且这行代码也不是牛顿第二定律的原理
Acceleration += Force;
然后我就思考一个问题,为何Mercury引擎的效果这么漂亮,然后我发现里面有一个文件夹叫做Textures,里面放着各种各样的贴图,比如下面这个名字为FlameFlare的图片(正常来说背景应该是透明的,左边我在背景加了颜色,右边是把图像的对比度加大)
在引擎中的效果如下(火焰效果)
是不是有种恍然大悟的感觉,原理炫丽的效果竟然是因为贴图的精心设计,我瞬间觉得我又有继续任职的必要了……当然为了保证我能够任职,我还要检测一下把图片放到我的粒子引擎是不是也会有同样炫丽的效果,于是……我把素材替换了一下,并且添加了这句话color = new Color(new Vector4(0.5509804f, 0.1509804f, 0.1509804f, alpha));……结果如下图
当然剩下的工作就是找原因,反编译了下源码
Color值跟我一样的定义啊,都是Vector4,xml里面的配置也是按rgb+opacity的格式给的,那这么扯淡的效果是什么原因呢?
当然我忘了自己是如何推导出这个解决方案的,反正我还是自行解决了,问题的关键在于spriteBatch.Begin的重载方式上,有一个重载方式要设定BlendState,就是颜色的混合方式,我们的代码如下
spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend);其实当时我也不知道应该把混合方式BlendState改成什么样子,于是一个个试了试,试到NonPremultiplied发现有如下效果