【Ogre引擎架构-第七讲】 爆破特效Explosion-粒子系统初体验
粒子系统作为一款图形引擎特效系统的核心而存在,Ogre的粒子系统经过专门的扩展插件的研发而变得功能强筋,绝不仅仅是一些OpenGL教材上的那些浅显的烟雾,喷泉效果,确切的说粒子系统主要还是一种架构设计的问题,本身所用算法含量还是比较有限的。这一讲,作者将通过爆破特效的实现过程,分析一下系统的实现原理和流程。
首先按照惯例,先来爆破效果的效果图(由于图片alpha通道问题,有一些锯齿效果),分别是爆破的几个阶段(起,中,末):
实现效果只需要一张图片:
通常一个粒子系统的构成是:System-Technique-Emitter-Affector-Renderer
System包含若干子系统Technique,Technique包含若干Emitter,Affector,Renderer,以及存储Emitter产生的粒子,Renderer负责根据粒子的属性信息产生相应的可渲染对象。
system explosion
{
category Explosion
technique Fire
{
visual_particle_quota 300
material PU/Nucleus
renderer billboard
{
billboard_type oriented_self
}
emitter Point FireEmitter
{
emission_rate 120
angle 360
time_to_live 1.5
velocity 1.8
duration 0.1
all_particle_dimensions dyn_random
{
min 0.6
max 2.4
}
color 0.8 0.8 0.8 1
}
affector Scale
{
xyz_scale dyn_curved_linear
{
control_point 0 60
control_point 0.3 0.6
control_point 1 0
}
}
affector TextureRotator
{
use_own_rotation true
rotation dyn_random
{
min 0
max 10
}
rotation_speed 0
}
affector Color
{
time_color 0 1 1 1 1
time_color 0.3 0.5 0.5 0.5 1
time_color 1.5 0.4 0.4 0.4 0.2
color_operation multiply
}
}
}
粒子系统对应的配置文件就是上面的结构。
System类:
class ParticleSystem:public Tomo::StringInterface,public Tomo::MovableObject
{
public:
ParticleSystem(const string& name,const string& resGroup);
virtual ~ParticleSystem();
virtual const string& GetMovableType() const ;
//render queue
virtual void UpdateRenderQueue(Tomo::RenderQueue* queue);
virtual const Tomo::AxisAlignedBox& GetBoundingBox() const {return m_AABB;}
virtual void NotifyAttached(Tomo::Node* parent);
//notify camera
virtual void NotifyCurrentCamera(Tomo::Camera* cam);
typedef vector<ParticleTechnique*> Techniques;
void AddTechnique(ParticleTechnique* tech);
float GetTimeElapsedSinceStart() const;
void Update(float timeElapsed);
protected:
string m_ResourceGroup;
Tomo::AxisAlignedBox m_AABB;
Tomo::Controller<float>* m_pTimeController;
Techniques m_Techniques;
float m_TimeElapsedSinceStart;
};
void ParticleSystem::ExecuteTriggerEmitters(ParticleEmitter* emitter,unsigned short requested,float timeElapsed)
{
if(!requested || !m_FreeParticles.size())
return ;
for(unsigned short i=0;i<requested;++i){
Particle* p(0);
string emitterName = emitter->GetEmittedEmitter();
if("" == emitterName)
p = CreateParticle();
else
;
if(!p)
return ;
emitter->InitParticle(p);
m_pRenderer->NotifyParticleEmitted(p);
}
}
void ParticleSystem::Expire(float timeElapsed)
{
Particle* p(0);
for(ActiveParticleList::iterator it=m_ActiveParticles.begin();
it!=m_ActiveParticles.end();){
p = *it;
if(p->timeToLive < timeElapsed){
m_FreeParticles.splice(m_FreeParticles.end(),m_ActiveParticles,it++);
}else{
p->timeToLive -= timeElapsed;
++it;
}
}
}
ParticleIterator ParticleSystem::GetIterator()
{
return ParticleIterator(m_ActiveParticles.begin(),m_ActiveParticles.end());
}
void ParticleSystem::TriggerAffecters(float timeElapsed)
{
ParticleAffector* affector(0);
for(ParticleAffectorList::iterator it=m_vAffectors.begin();
it!=m_vAffectors.end();++it){
affector = *it;
affector->AffectParticles(this,timeElapsed);
}
}
上面的TriggerEmitter,TriggerAffector分别展示了,发射器Emiiter和影响器Affector的应用过程。
Emitter类,Affector类:
void ParticleEmitter::InitParticle(Particle* pParticle)
{
Vector3 Off;
Off.x = 0.8f*Math::SymmetricRandom();
Off.y = 0.8f*Math::SymmetricRandom();
//Off.z = 1.f*Math::SymmetricRandom();
pParticle->position = m_Position+Off;
InitParticleDirection(pParticle);
pParticle->timeToLive = m_MaxTTL;
float dim = m_pDynAllParticleDimens->GetValue();
pParticle->width = dim;
pParticle->height = dim;
pParticle->color = m_Color;
pParticle->origin_color = m_Color;
}
void ColorAffector::Affect(ParticleTechnique* technique,Particle* pParticle,float timeElapsed)
{
ColorValue time_color;
float time = technique->GetParentSys()->GetTimeElapsedSinceStart();
TimeColorMap::iterator it = m_mTimeColors.begin();
for(;it!=m_mTimeColors.end();++it){
if(time < it->first){
if(it == m_mTimeColors.begin())
break;
else{
--it;
break;
}
}
}
if(it == m_mTimeColors.end())
--it;
TimeColorMap::iterator it2 = it;
++it2;
if(it2 != m_mTimeColors.end()){
time_color = it->second+(it2->second - it->second)*((time-it->first)/(it2->first-it->first));
}else{
time_color = it->second;
}
pParticle->color = pParticle->origin_color*time_color;
}
void ScaleAffector::Affect(ParticleTechnique* technique,Particle* pParticle,float timeElapsed)
{
if(m_pDynXYZScale){
float scale = m_pDynXYZScale->GetValue(technique->GetParentSys()->GetTimeElapsedSinceStart())*timeElapsed;
pParticle->width += scale;
pParticle->height += scale;
//
}
}
void TextureRotatorAffector::Affect(ParticleTechnique* technique,Particle* pParticle,float timeElapsed)
{
if(m_pDynRotator){
float angle = m_pDynRotator->GetValue()*timeElapsed;
angle /= 2*PI;
if(pParticle->m_ZRotate)
angle*=-1.f;
Tomo::Matrix rot;
rot.MakeRotateZ(angle);
pParticle->direction = rot*pParticle->direction;
}
}
Renderer类,负责产生可渲染的粒子对象:(读者可以自行参考Ogre的BillboardParticleRenderer类)
void BillboardParticleRenderer::UpdateRenderQueue(RenderQueue* queue,list<Particle*>& currentParticles,bool cullIndividual)
{
m_pBillboardSet->SetCullIndividually(cullIndividual);
//update billboard set geometry
m_pBillboardSet->BeginBillboards(currentParticles.size());
Billboard bb;
for(list<Particle*>::iterator it=currentParticles.begin();it!=currentParticles.end();++it){
Particle* p = *it;
bb.m_Pos = p->position;
bb.m_Color = p->color;
bb.m_Direction = p->direction;
bb.m_Width = p->width;
bb.m_Height = p->height;
m_pBillboardSet->InjectBillboard(bb);
}
m_pBillboardSet->EndBillboards();
m_pBillboardSet->UpdateRenderQueue(queue);
}
void BillboardSet::InjectBillboard(const Billboard& bb)
{
if(m_NumVisibleBillboards == m_PoolSize)
return ;
//if(!BillboardVisible(bb))
// return ;
if(m_PointRendering){
GenVertices(0,bb);
}else{
//gen billboard axes
GenBillboardAxes(&m_CamX,&m_CamY,&bb);
if(m_AllDefaultSize){
//gen offsets
GenVertOffsets(m_DefaultWidth,m_DefaultHeight);
}else
GenVertOffsets(bb.m_Width,bb.m_Height);
//gen vertices
GenVertices(m_VOffset,bb);
}
++m_NumVisibleBillboards;
}
void BillboardSet::GenVertices(const Vector3* const offsets,const Billboard& b)
{
if(m_PointRendering){
*m_pLockMainBuffer++ = b.m_Pos.x;
*m_pLockMainBuffer++ = b.m_Pos.y;
*m_pLockMainBuffer++ = b.m_Pos.z;
RGBA color = b.m_Color.GetAsRGBA();
RGBA* pColor = static_cast<RGBA*>(static_cast<void*>(m_pLockMainBuffer));
*pColor++ = color;
m_pLockMainBuffer = static_cast<float*>(static_cast<void*>(pColor));
}else{
static FloatRect texRect(0.f,0.f,1.f,1.f);
//vertex0
*m_pLockMainBuffer++ = m_VOffset[0].x+b.m_Pos.x;
*m_pLockMainBuffer++ = m_VOffset[0].y+b.m_Pos.y;
*m_pLockMainBuffer++ = m_VOffset[0].z+b.m_Pos.z;
//color
RGBA color = b.m_Color.GetAsRGBA();
RGBA* pColor = static_cast<RGBA*>(static_cast<void*>(m_pLockMainBuffer));
*pColor++ = color;
m_pLockMainBuffer = static_cast<float*>(static_cast<void*>(pColor));
//tex coords
*m_pLockMainBuffer++ = texRect.left;
*m_pLockMainBuffer++ = texRect.top;
//vertex1
*m_pLockMainBuffer++ = m_VOffset[1].x+b.m_Pos.x;
*m_pLockMainBuffer++ = m_VOffset[1].y+b.m_Pos.y;
*m_pLockMainBuffer++ = m_VOffset[1].z+b.m_Pos.z;
//color
pColor = static_cast<RGBA*>(static_cast<void*>(m_pLockMainBuffer));
*pColor++ = color;
m_pLockMainBuffer = static_cast<float*>(static_cast<void*>(pColor));
//tex coords
*m_pLockMainBuffer++ = texRect.right;
*m_pLockMainBuffer++ = texRect.top;
//vertex2
*m_pLockMainBuffer++ = m_VOffset[2].x+b.m_Pos.x;
*m_pLockMainBuffer++ = m_VOffset[2].y+b.m_Pos.y;
*m_pLockMainBuffer++ = m_VOffset[2].z+b.m_Pos.z;
//color
pColor = static_cast<RGBA*>(static_cast<void*>(m_pLockMainBuffer));
*pColor++ = color;
m_pLockMainBuffer = static_cast<float*>(static_cast<void*>(pColor));
//tex coords
*m_pLockMainBuffer++ = texRect.left;
*m_pLockMainBuffer++ = texRect.bottom;
//vertex3
*m_pLockMainBuffer++ = m_VOffset[3].x+b.m_Pos.x;
*m_pLockMainBuffer++ = m_VOffset[3].y+b.m_Pos.y;
*m_pLockMainBuffer++ = m_VOffset[3].z+b.m_Pos.z;
//color
pColor = static_cast<RGBA*>(static_cast<void*>(m_pLockMainBuffer));
*pColor++ = color;
m_pLockMainBuffer = static_cast<float*>(static_cast<void*>(pColor));
//tex coords
*m_pLockMainBuffer++ = texRect.right;
*m_pLockMainBuffer++ = texRect.bottom;
}
}
GenVertices函数中对HardwareBuffer的填充,参考
【第四讲-HardwareBuffer】。
相关文章
- 1. Ogre引擎粒子系统
- 2. 【Ogre引擎架构】 第十二讲 粒子系统-飘雪之国
- 3. 粒子系统
- 4. android 粒子爆炸特效
- 5. Ogre 粒子系统及粒子脚本
- 6. Unity粒子系统特性
- 7. OGRE粒子系统参数
- 8. Ogre粒子系统简介
- 9. Android制作粒子爆炸特效
- 10. 第十章 OGRE中的粒子系统
- 更多相关文章...
相关标签/搜索