【Ogre引擎架构】第七讲 粒子系统-爆破特效
2015-10-04 18:18
567 查看
粒子系统作为一款图形引擎特效系统的核心而存在,Ogre的粒子系统经过专门的扩展插件的研发而变得功能强筋,绝不仅仅是一些OpenGL教材上的那些浅显的烟雾,喷泉效果,确切的说粒子系统主要还是一种架构设计的问题,本身所用算法含量还是比较有限的。这一讲,作者将通过爆破特效的实现过程,分析一下系统的实现原理和流程。
首先按照惯例,先来爆破效果的效果图(由于图片alpha通道问题,有一些锯齿效果),分别是爆破的几个阶段(起,中,末):
实现效果只需要一张图片:
通常一个粒子系统的构成是:System-Technique-Emitter-Affector-Renderer
System包含若干子系统Technique,Technique包含若干Emitter,Affector,Renderer,以及存储Emitter产生的粒子,Renderer负责根据粒子的属性信息产生相应的可渲染对象。
System类:
Emitter类,Affector类:
首先按照惯例,先来爆破效果的效果图(由于图片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】。
相关文章推荐
- dede 常用网站开发标签
- Hbase笔记二:简明系统架构
- Hadoop YARN架构设计要点
- Yahoo!团队实践分享:网站性能优化的34条黄金守则
- Loadrunner自带的网站WebTours打不开
- 网站关键词优化--如何确6定目标关键词
- 网站用户存在状态的session用法及例子
- 关注的网站
- MVC在Web系统中的模式与应用--架构模式
- <从编程到(架构)设计之路>的翻转式系列课程
- Heartbleed 实战:一个影响无数网站的缓冲区溢出漏洞
- JS控制网站样式改变的原理
- 网站字体影印代码!
- 网站导航标题栏下面是几个补丁尾随鼠标移动,当同样的颜色变化效果的颜色
- 微网站|手机端html弹窗、弹层、提示框、加载条
- 网站伸缩性架构
- 高可用应用层
- 网站高可用服务
- 网站高可用数据
- ***************架构师**********************