摘要:本文阐述了如何利用C++的Template开发出方便组装,适合各种应用的泛型粒子系统,开发过程中使用到了Boost.Mpl和Boost.Random。
关键字:粒子系统,泛型编程,Boost
〇、引言
在各种3D应用中,粒子系统扮演着举足轻重的角色。雨雪的模拟、流水的模拟、火焰的模拟等等都离不开粒子系统。传统的粒子系统的开发很难同时满足各种各样的需要,只能针对特定的应用做特定的开发,有没有什么方法可以开发出适合各种应用的粒子系统呢?这让我们想到了求助C++的Template。
一、 粒子结构
在传统的粒子系统中我们常看到这样的粒子结构的定义。
struct SParticle {
tVector3 m_vPos;
tVector3 m_vVel;
tColor m_cColor;
tReal m_rFade;
tReal m_rLife;
};
这样做的缺点就是整个粒子的结构被固定死了,无法适应不同的需要,针对不同类型的粒子就必须定义不同的结构。为了解决这个问题我们把粒子拆分成不同的部分,这样就可以按需要进行组装,并且针对粒子的特定部分制定的算法可以得到充分的复用。我们可以做如下拆分:
// 粒子位置
struct SParticlePos {
tVector3 m_vPos;
};
// 粒子速度
struct SParticleVel {
tVector3 m_vVel;
};
// 粒子颜色
struct SParticleColor {
tColor m_cColor;
};
// 粒子退色因子
struct SParticleFade {
tReal m_rFade;
};
// 粒子寿命
struct SParticleLife {
tReal m_rLife;
};
把粒子拆分以后我就需要一个组装机制。
// 粒子组装器
template<
class _PartIter,
class _PartsVector
> class TParticlePartHolder
: public boost::mpl::deref< _PartIter >::type,
, public TParticlePartHolder< _PartIter::next >
{};
template<
class _PartsVector
> class TParticlePartHolder< boost::mpl::end< _PartsVector >::type, _PartsVector >
: public boost::blank
{};
这里用到了Boost的mpl库中的类型序列容器作为粒子组装器的_PartsVector模板参数,它可以是boost::mpl::vector或其它与之兼容的类型序列容器,用于容纳粒子个各个不同部分。_PartsIter模板参数是_PartsVector的一个跌代器,它指向了位于_PartsVector中的一个粒子部分。TParticlePartHolder是一个自递归继承的模板类,递归结束条件由一个偏特化的TParticlePartHolder确定。粒子组装器每一次递归继承一个_PartIter所指向的粒子部分(通过boost::mpl::deref<>获取),并把_PartIter向后移动一次传入下一次递归,直到_PartIter指向了_PartsVector容器的末端(继承一个空类boost::blank)。
有了粒子组装器我们还需要一个名为TParticlePolicy的模板类把它包装起来。
// 粒子
template<
class _PartsVector
> struct TParticlePolicy
: public TParticlePartHolder< boost::mpl::begin< _PartsVector >::type, _PartsVector >
{
typedef _PartsVector tPartsVector;
// 部分数
static const int s_ciNumOfParts = boost::mpl::size< _PartsVector >::type::value;
}
TPaticlePolicy接受一个名为_PartsVector的类型序列容器,并以指向_PartsVector首的迭代器(通过boost::mpl::begine<>获取)和_PartsVector作为参数继承TParticlePartHolder。
现在就可以个把各个不同的粒子部分组装起来了。如组装一个具有位置、速度、颜色和寿命等属性的粒子我们可以这样写代码:
TParticlePolicy<
boost::mpl::vector<
SParticlePos,
SParticleVel,
SParticleColor,
SParticleLife
>
>
看到这里也许您还有一些不太清楚,让我们用一张继承结构图来说明: