粒子系统实现要点。
根据之前设计粒子系统的思路整理。
要正确处理:粒子(particle),发射器(emitter),力场(Force),粒子系统(particle system)之间的关系。
粒子的生命期由:有发射器产生,并设置初始的生命值。在整个生命周期中受力场影响(力场只影响粒子的轨迹,不会影响到其他因素),其消亡可以跟随粒子系统的消亡而消亡也可以独立存在。
发射器:即指发射器的模板,也包括发射器详细定义。
发射器模板中要定义的是:
1、材质信息,shader中要处理序列帧的情况。
2、大的类型:公告牌还是拖尾特效,以及拖尾特效的参数(平滑度)
3、粒子初始设置的设置(大小,颜色等)。
发射器详细定义 指明了引用哪个发射器模板,并在模板的基础上增加定义了:
1、发射器的形状:指定了平面四边形,平面圆环,圆锥,立方体,球,半球。其中,除了立方体以外,其他的都是在表面发射的。
2、指定粒子的更新方式。按照粒子系统更新于按照粒子本身更新,只是决定初始的颜色等参数的取值。这个相当于时间轴是否需要根据粒子系统作调整。
3、设置初始的发射方向,这个是根据散射角度范围来设定的。散射角度定义为绕x轴的旋转的方向,绕y轴的方向为-pi/2,pi/2之间的随机值。
力场定义了 粒子受力的情况。通常力场也有一个时间轴。力场的参数值可以随时间进行变化。实现了一下的力场,要注意的是 通常力场是在世界坐标系中被定义的,力的作用时间t为力场调用的帧间隔:
1、重力:直接设置的重力值
2、风力:表现为风力参数再叠加一个随机值。
3、旋风:表现为粒子与力在xoz平面的一个向心速度。
4、旋转:表现为粒子绕某个轴进行旋转,主要定义 旋转轴与旋转参数。
5、布朗运动:表现为在原点进行随机的抖动效果。
这里需要注意的是:通常力场是与粒子分离的,一个发射器发射的粒子可能同时受多个力场影响,同样,一个力场也能同时影响多个发射器发射的粒子。
粒子表现支持:
1、普通公告牌:垂直与视野,用得最多,计算也最简单
2、基于速度方向的公告牌:换算到世界坐标系,计算世界坐标系下位移的变化来确定速度方向,然后镜头与当前位置的方向为法线方向,cross(normal,realveloc)的方向为billboard的一个轴,另外一个为realveloc即可。计算量较大。建议改成模型来处理。
3、垂直局部坐标xoz:取得local up,up.z = 0,up.normalize().eyedirect = cross(cameraRight, up),eyedirect.normalize().right = cross(up,eyedirect),right.normalize() 即可得到billboard的两个轴了。
其他的类推,只是注意将local up换成世界坐标中的up即可。
4、树叶:表现为世界坐标系中的垂直xoz的billboard,随机旋转一个方向。
粒子更新由于计算量比较巨大,通常有以下的思路来优化:
尽量使用相似的计算:用lerp代替slerp等。
多线程处理,由于此处直接更新的VBO,因此跟多线程渲染牵扯在一起,另外再讲。
上面还提到了拖尾的粒子,这个要注意的是,此时的粒子不再表示为一个点 spirte,而是一个mesh,这个mesh通常是根据同一个粒子相邻的两个状态(主要是坐标点的位置),来产生一个四边形面,这个面同样具有自己的生命周期。
主要是通过坐标点距离的大小来判断是否要增加一个节点的。
这个会导致计算量与渲染顶点数增加。
粒子系统:主要用来协同发射器,力场,与粒子之间关系的。
通常的调用代码如下
//伪代码 void ParticleSystem::update( float delta ) { if(emitter == NULL) return; if( needCreateParticle() ) { Particle* array = 0; unsigned int particleCount = emitter->emitter( currentFrame,preFrame, array ); if( array!= NULL && particleCount!= 0 ) { if( mParticleCount + particleCount > mParticles.size() ) mParticles.resize( mParticleCount + particleCount ); Add2ParticlePool(array,particleCount); } if( mParticleCount == 0 ) return; updateForce();//更新力场 updateParticles();//更新自身 }
更新力场主要是设置力场对速度的影响。
粒子更新自身的时候,要根据速度来计算位置,根据时间轴来更新颜色,大小,旋转角度,帧动画的对应帧。
从上面来看,粒子系统基本上没有任何理解上的难度,主要的难点在与代码编写时的优化过程。
这里主要的原因在于,力场基本上都是描述在世界坐标系中的,如果粒子是局部坐标的粒子,(比如粒子跟随粒子系统移动的情况下,需要转换成世界坐标轴计算力场的影响)。另外粒子本身数量比较巨大,要注意缓存一些常用的数据。
比如获取镜头方向等。
另外粒子的表现形式与运动坐标系可能不相同,比如运动坐标系是参照世界坐标系的,但是粒子表现是基于局部坐标系的(相对于粒子系统的)。这时候需要做坐标系的转换。
总体一条是要限制矩阵的求逆。
浙公网安备 33010602011771号