MercuryParticleEngine的研究与本质分析

        昨天偶然发现了XNA粒子系统的一个神器——Mercury Particle Engine 3.1 for XNA 4.0 (Binaries)。拿到这个引擎用了一下,第一感觉就是我这个在团队中负责做特效的可以被撤职了,而且是自己把自己撤了!因为Mercury粒子引擎做的实在是太好太漂亮,而且引用也方便。下面是这个引擎“光束”特效的一个截图

    MercuryParticleEngine的研究与本质分析_第1张图片

怎么样?看到之后颤抖吧!我仰天长叹,国内的程序员都死哪了?!怎么都是国外的在做这种引擎,而且虽然不是开源,不过用反编译工具是很轻易的窥视作者的代码的。

感叹完了,今天又把这个系统研究了一番,并且反编译了一下看了下源码发现其实是我写粒子效果的思路出了问题,其实Mercury引擎的算法基础是很简单的。

粒子引擎通用的算法机制

Speed += Acceleration;

Position += Speed;

Rotation += AngularSpeed;

Color = F(gametime);

Scale = F(gametime);

当然在Mercury引擎中又针对加速度多了一个方程。我觉得并不是十分必要,因为从物理角度来说Force跟Acceleration其实是靠质量mass来连接,而且这行代码也不是牛顿第二定律的原理

Acceleration += Force;

然后我就思考一个问题,为何Mercury引擎的效果这么漂亮,然后我发现里面有一个文件夹叫做Textures,里面放着各种各样的贴图,比如下面这个名字为FlameFlare的图片(正常来说背景应该是透明的,左边我在背景加了颜色,右边是把图像的对比度加大)

  MercuryParticleEngine的研究与本质分析_第2张图片                MercuryParticleEngine的研究与本质分析_第3张图片

在引擎中的效果如下(火焰效果)

MercuryParticleEngine的研究与本质分析_第4张图片

是不是有种恍然大悟的感觉,原理炫丽的效果竟然是因为贴图的精心设计,我瞬间觉得我又有继续任职的必要了……当然为了保证我能够任职,我还要检测一下把图片放到我的粒子引擎是不是也会有同样炫丽的效果,于是……我把素材替换了一下,并且添加了这句话color = new Color(new Vector4(0.5509804f, 0.1509804f, 0.1509804f, alpha));……结果如下图

MercuryParticleEngine的研究与本质分析_第5张图片

我瞬间觉得我被坑了……

当然剩下的工作就是找原因,反编译了下源码

MercuryParticleEngine的研究与本质分析_第6张图片

Color值跟我一样的定义啊,都是Vector4,xml里面的配置也是按rgb+opacity的格式给的,那这么扯淡的效果是什么原因呢?

除了自己弱还能是神马原因……

当然我忘了自己是如何推导出这个解决方案的,反正我还是自行解决了,问题的关键在于spriteBatch.Begin的重载方式上,有一个重载方式要设定BlendState,就是颜色的混合方式,我们的代码如下

spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend);其实当时我也不知道应该把混合方式BlendState改成什么样子,于是一个个试了试,试到NonPremultiplied发现有如下效果

MercuryParticleEngine的研究与本质分析_第7张图片

咳咳,终于算是解决了。

那NonPremultiplied到底是什么意思呢?下面仅仅是我个人的猜测。

首先Premultiplied是一种处理图像透明度的方式,可以参照这篇文章http://rintarou.dyndns.org/2010/04/27/premultiplied-alpha/,也就是说Premultiplied是把图像中的alpha值事先分配给了rgb值,这样的话会提高一定的运算效率。但是问题就在这里,如果说图像本身的alpha值分配被提前分配好了,那么修改spriteBatch.Draw中的color值相当于把原图又重新刷了一遍,图片本身的alpha值的分布会因为color中的alpha后赋值而变得整体alpha值都一样,出现上面“纯色”的效果。但是如果spriteBatch.Draw中的color与原图的color共同考虑,也就是说真正的R值为R = (color.R * color.alpha + imagepixel.R * imagepixel.alpha) / 2 这样的话就避免了图片“纯色”的现象。
XNA给出的英文解释如下
// 摘要:
        //     A built-in state object with settings for blending with non-premultipled
        //     alpha,
that is blending source and destination data using alpha while assuming
        //     the color data contains no alpha information.
红字部分其实就是我对于公式R = (color.R * color.alpha + imagepixel.R * imagepixel.alpha) / 2的印证吧。

解决了XNA粒子的一大问题啊!以前我还以为火焰效果是拿一大堆的“颗粒”堆砌而成,没想到竟然是拿贴图来做的,而且只含透明度信息的贴图对于颜色的修改也会提供很大的自由。
最终还是赞美一下MercuryParticleEngine!
There is still a lot for me to go through!

MercuryParticleEngine的研究与本质分析_第8张图片


你可能感兴趣的:(粒子系统)