【Ogre引擎架构-第七讲】 爆破特效Explosion-粒子系统初体验 脚本

【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】。
相关文章
相关标签/搜索
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值