笔者:i_dovelemon

资源:CSDN

日期:2014 / 10 / 16

主题:Point Sprite, Particle System

介绍

在游戏中。非常多的绚丽,灿烂的特效,都能够使用粒子系统制作出来。那么粒子系统。究竟是什么?它是怎样工作的?接下来的文章,将会向大家讲述怎样构建一个简单的粒子系统。

粒子系统

所谓的粒子系统,指的是一个粒子管理器,用于在特定条件下产生特定的粒子。而且赋予粒子以运动。

所以,可以将粒子系统看成是一个个粒子的集合。

而不同的效果。是要我们自己来控制粒子怎样产生,粒子的颜色怎样变化,粒子怎样进行运动。通过控制这些条件,我们就行创造出非常多非常多的特效出来。而关键就在于怎样控制粒子的运动和产生。

既然,我们明确了粒子系统的概念。那么一个粒子究竟是什么?它在计算机中是怎样进行表示的?

简单而言。粒子在计算机中就是使用一个结构来表达。结构中保存了粒子的基本属性,如位置,颜色。生命,以及运动状态相关的參数。不同复杂度的粒子系统,粒子所包括的属性并不同样。假设须要简单的效果。那么仅仅须要几个主要的属性就可以。假设要做出更加复杂。或者更加符合动力学的粒子系统,能够在结构中再加入非常多不同的物理属性。至于怎样加入这些属性,要依赖于你所须要实现的粒子系统的复杂程度,想要支持的功能来进行设计。

当我们为粒子系统设计好了一个粒子结构之后。而且也有了粒子系统。来负责粒子的产生,以及运动等等。我们须要的当然就是显示在界面上。假设没有显示不论什么的内容,即使你的系统再强大,也是白费力气。

DirectX中支持非常多的基本单元类型,最经常使用的如三角形列表,线条列表等等。

在这里,我们将会使用一个称之为Point Sprite的基本单元类型。

Point Sprite。实际上就是一个点。

我们在应用程序阶段,仅仅须要将它当做点进行处理就可以。可是要显示效果,我们自然还是须要进行纹理映射。因为Point Sprite的特殊性。DirectX内部会自己主动的为这些点设置纹理坐标。注意,这里的点仅仅是逻辑意义上的。

DirectX在最后处理的时候。还是会使用多边形来进行处理。

所以这里说的点,存在一个大小的问题。我们可以通过程序来控制产生的点的大小。

为了实现一些效果,我们须要开启Alpha blend。毕竟做粒子特效,假设没有进行颜色混合的话。就是一个一个的单独的纹理,这并非粒子效果了。

并且。粒子在界面显示的时候的先后顺序,对于我们来说并不重要。所以,将depth test以及depth buffer禁用掉,可以提高系统的效率。

基本类的设计

在上面,说了这么多,终于要体如今代码上面。以下是粒子系统的抽象类。当我们须要创建一个新的效果的时候,仅仅要继承这个类,而且复写虚函数就可以。当然,这里的仅仅是一个非常easy的粒子系统设计,提供的粒子属性也非常少。可是也可以做出非常多的效果出来了。假设读者。希望更复杂的效果,就行自己来扩展这个基本类别。然后加入你自己的功能。

废话不多说,直接上代码:

//-----------------------------------------------------------------------
// declaration  : Copyright (c), by XJ , 2014. All right reserved .
// brief        : This file will define the Particle system
// author       : XJ
// file         : PSystem.h
// date         : 2014 / 10 / 15
// version      : 1.0
//-----------------------------------------------------------------------
#pragma once#include<d3dx9.h>
#include"AABB.h"
#include"Camera.h"
#include<vector>
using namespace XJCollision ;
using namespace std ;struct Particle
{D3DXVECTOR3 initPos ;D3DXVECTOR3 initVelocity;float        initSize    ;       //in pixelfloat       initTime  ;float      lifeTime    ;float      mass        ;D3DXCOLOR  initColor   ;static IDirect3DVertexDeclaration9*    decl ;
};class PSystem
{
public:PSystem(const char* fxName,const char* techName,const char* texName,const D3DXVECTOR3& accel,const AABB& box,int maxNumParticles,float timePerParticle,LPDIRECT3DDEVICE9 device,Camera* camera);virtual ~PSystem();public:float getTime();void setTime(float fTime);const AABB& getAABB() const ;void setWorldMtx(const D3DXMATRIX& world);void addParticle();virtual void onLostDevice();virtual void onResetDevice();virtual void initParticles(Particle& out) = 0;virtual void update(float dt);virtual void draw() ;protected:LPDIRECT3DDEVICE9 m_pDevice;              // DeviceID3DXEffect        *m_FX   ;                   // EffectD3DXHANDLE      m_hTech;                   // TechniqueD3DXHANDLE       m_hWVP ;                   // WVP matrixD3DXHANDLE      m_hEyePosL;                // D3DXHANDLE        m_hTex;                    // TextureD3DXHANDLE         m_hTime;                   // TimeD3DXHANDLE        m_hAccel;                  // AccelD3DXHANDLE       m_hViewportHeight;         // Viewport's heightIDirect3DTexture9* m_Tex;                  // TextureIDirect3DVertexBuffer9* m_VB  ;           // Vertex bufferD3DXMATRIX       m_World;                   // World matrixD3DXMATRIX        m_InvWorld;                // Inverse matrixfloat           m_Time ;                   // TimeD3DXVECTOR3       m_Accel ;                  // AccelerateAABB            m_AABB;                    // Bounding boxint               m_MaxNumParticles;         // Max number particlesfloat             m_fTimePerParticle;        // Delay time to emit one particleCamera            *m_pCamera  ;               // Camerastd::vector<Particle>    m_Particles;        // Particles liststd::vector<Particle*>  m_AliveParticles;    // Alive particles liststd::vector<Particle*> m_DeadParticles;    // Dead particles list
};// end for PSystem
#include"PSystem.h"
#include"MyUtil.h"
#include<d3dx9.h>IDirect3DVertexDeclaration9* Particle::decl = NULL ;
/**
* Constructor
*/
PSystem::PSystem(const char* fxName,const char* techName,const char* texName,const D3DXVECTOR3& accel,const AABB& box,int maxNumParticles,float timePerParticle,LPDIRECT3DDEVICE9 device,Camera* camera)
{//Save the devicem_pDevice = device ;//Create error bufferID3DXBuffer* _error = NULL ;HR(D3DXCreateBuffer(128, &_error));//Create the EffectHR(D3DXCreateEffectFromFileA(m_pDevice, fxName,NULL,NULL, D3DXSHADER_DEBUG, NULL, &m_FX, &_error));//If error if(_error){MessageBoxA(NULL,(char*)_error->GetBufferPointer(),"Error", MB_OK);return ;}//Get the technique handlem_hTech = m_FX->GetTechniqueByName(techName);//Get all the handlem_hWVP = m_FX->GetParameterByName(0, "gWVP");m_hEyePosL = m_FX->GetParameterByName(0, "gEyePosL");m_hTex = m_FX->GetParameterByName(0, "gTex");m_hTime = m_FX->GetParameterByName(0, "gTime");m_hAccel = m_FX->GetParameterByName(0, "gAccel");m_hViewportHeight = m_FX->GetParameterByName(0, "gViewportHeight");//Create the textureHR(D3DXCreateTextureFromFileA(m_pDevice, texName, &m_Tex));//Set parametersHR(m_FX->SetTechnique(m_hTech));HR(m_FX->SetTexture(m_hTex, m_Tex));HR(m_FX->SetVector(m_hAccel, &D3DXVECTOR4(m_Accel,0.0f)));//Save the time per particlesm_fTimePerParticle = timePerParticle ;m_Time = 0.0f ;//Save the AABBm_AABB = box ;//Save the cameram_pCamera = camera ;//Allocate the memory for the particlem_MaxNumParticles = maxNumParticles ;m_Particles.resize(m_MaxNumParticles);m_AliveParticles.reserve(m_MaxNumParticles);m_DeadParticles.reserve(m_MaxNumParticles);//They start all deadfor(int i = 0 ; i < m_MaxNumParticles ; i ++){m_Particles[i].initTime = 0.0f ;m_Particles[i].lifeTime = -1.0f ;}//Create the vertex bufferHR(m_pDevice->CreateVertexBuffer(m_MaxNumParticles * sizeof(Particle), D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY|D3DUSAGE_POINTS,0,D3DPOOL_DEFAULT,&m_VB,NULL));
}// end for constructor/**
* Destructor
*/
PSystem::~PSystem()
{m_AliveParticles.clear();m_DeadParticles.clear();m_Particles.clear();m_FX->Release();m_Tex->Release();m_VB->Release();
}// end for destructorvoid PSystem::setTime(float fTime)
{m_Time = fTime ;
}// end for setTimevoid PSystem::setWorldMtx(const D3DXMATRIX& world)
{m_World = world ;D3DXMatrixInverse(&m_World,NULL,&m_World);
}// end for setWorldMtxvoid PSystem::addParticle()
{if(m_DeadParticles.size() > 0){Particle* p = m_DeadParticles.back();initParticles(*p);m_DeadParticles.pop_back();m_AliveParticles.push_back(p);}
}// end for addParticlevoid PSystem::onLostDevice()
{//OnlostDevice for fxm_FX->OnLostDevice();if(m_VB){m_VB->Release();m_VB = NULL ;}
}// end for onLostDevicevoid PSystem::onResetDevice()
{//OnResetDevice for fxm_FX->OnResetDevice();if(m_VB){//Recreate the vertex bufferHR(m_pDevice->CreateVertexBuffer(m_MaxNumParticles*sizeof(Particle),D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY|D3DUSAGE_POINTS,0,D3DPOOL_DEFAULT,&m_VB,NULL));}
}// end for onResetDevicevoid PSystem::update(float dt)
{m_Time += dt ;//Rebuild the dead list and alive listm_DeadParticles.resize(0);m_AliveParticles.resize(0);//For each particlefor(int i = 0 ; i < m_Particles.size() ; i ++){if((m_Time - m_Particles[i].initTime) > m_Particles[i].lifeTime){m_DeadParticles.push_back(&m_Particles[i]);}else{m_AliveParticles.push_back(&m_Particles[i]);}}// end for //Check if it is the time to emit one another particleif(m_fTimePerParticle > 0.0f){static float timeDelay = 0.0f ;timeDelay += dt ;if(timeDelay > m_fTimePerParticle){addParticle();timeDelay = 0.0f ;}}
}// end for updatevoid PSystem::draw()
{//Get the camera's position in the world and make it relative to the particle system's local systemD3DXVECTOR3 eyeW = m_pCamera->pos();D3DXVECTOR3 eyeL ;D3DXVec3TransformCoord(&eyeL, &eyeW, &m_InvWorld);//Set the FX parameterHR(m_FX->SetValue(m_hEyePosL,&eyeL,sizeof(D3DXVECTOR3)));HR(m_FX->SetFloat(m_hTime, m_Time));HR(m_FX->SetMatrix(m_hWVP, &(m_World* m_pCamera->viewproj())));HR(m_FX->SetInt(m_hViewportHeight, 600));//Draw//set the vertex bufferHR(m_pDevice->SetStreamSource(0, m_VB, 0, sizeof(Particle)));//set the vertex declarationHR(m_pDevice->SetVertexDeclaration(Particle::decl));Particle* p = 0 ;HR(m_VB->Lock(0, 0, (void**)&p, D3DLOCK_DISCARD));UINT vIndex = 0 ;for(int i = 0 ; i < m_AliveParticles.size(); i ++){p[vIndex] = *m_AliveParticles[i] ;vIndex ++ ;}// end forHR(m_VB->Unlock());UINT numPass = 0 ;HR(m_FX->Begin(&numPass, 0));HR(m_FX->BeginPass(0));if(vIndex > 0){m_pDevice->DrawPrimitive(D3DPT_POINTLIST,0,vIndex);}HR(m_FX->EndPass());HR(m_FX->End());
}// end for draw

我在这个类的基础上继承了一个类,用于实现自己的效果:

#pragma once#include"PSystem.h"class FireRing: public PSystem
{
public:FireRing(const char* fxName,const char* techName,const char* texName,const D3DXVECTOR3& accel,const AABB& box,int maxNumParticles,float timePerParticle,LPDIRECT3DDEVICE9 device,Camera* camera):PSystem(fxName, techName, texName, accel,box, maxNumParticles, timePerParticle, device, camera){};void initParticles(Particle& out){//Save the init timeout.initTime = m_Time ;//Calculate the life time from 2.0s to 4.0sout.lifeTime = 20.0f + 2 * (rand()%10001 * 0.0001) ;//Calculate the initialize size in pixelout.initSize = 50.0f + 10 * (rand()%10001 * 0.0001) ;//Calculate the a very small velocitystatic float angle = 0.0f ;D3DXVECTOR3 vel(0.5f, 1.0f, 0.5f);D3DXMATRIX m ;D3DXMatrixRotationY(&m,angle);D3DXVec3TransformCoord(&vel, &vel, &m);out.initVelocity = vel ;D3DXVec3Normalize(&out.initVelocity, &out.initVelocity);angle += 1.0f ;//Calculate the massout.mass = 1.0f + (rand()%10001 * 0.0001) ;//Calculate the colorfloat t = (0.5f + 0.5*(rand()%10001 * 0.0001)) ;out.initColor = D3DXCOLOR(0.0f, 0.0f, t * 1.0f, t * 1.0f);//Calculate the posout.initPos.x = 0.0f;out.initPos.y = 0.0f ;out.initPos.z = 0.0f ;}// end for initParticle
};

这个类仅仅要复写它的粒子初始化函数就行了。通过在初始化的里面进行设计。改变粒子的位置,状态等等,我们还是可以做出非常多的效果出来。

以下是这个效果配套的Shader:

uniform extern float4x4 gWVP ;
uniform extern texture gTex ;
uniform extern float3  gEyePosL;
uniform extern float3  gAccel ;
uniform extern float   gTime ;
uniform extern float   gViewportHeight ;sampler TexS = sampler_state
{Texture = <gTex>;MinFilter = LINEAR ;MagFilter = LINEAR ;MipFilter = POINT  ;AddressU = CLAMP ;AddressV = CLAMP ;
};struct OutputVS
{float4 posH : POSITION ;float4 color: COLOR0   ;float2 tex0 : TEXCOORD0 ;float  size : PSIZE ;
};//VS
OutputVS FireRingVS(float3 posL: POSITION,float3 vel : TEXCOORD0,float size : TEXCOORD1,float time : TEXCOORD2,float lifeTime: TEXCOORD3,float mass : TEXCOORD4,float4 color: COLOR0
)
{//Clear the outputOutputVS outVS = (OutputVS)0 ;float t = gTime - time ;posL = posL + t * vel ;outVS.posH = mul(float4(posL,1.0f), gWVP);size += 0.8 * t ;float d = distance(posL, gEyePosL);outVS.size = size ; //gViewportHeight * size / (1.0 + 8.0f*d);color.r = 0.0f ;color.g = 0.0f ;color.b = 1.0f * (t / lifeTime) ; color.a = 1.0f - 1.0f * (t / lifeTime) ; outVS.color = color ;//(1.0f - (t / lifeTime)) ;return outVS ;
}//PS
float4 FireRingPS(float4 color:COLOR0,float2 tex0: TEXCOORD0):COLOR
{return color * tex2D(TexS, tex0);
}technique FireRingTech
{pass P0{vertexShader = compile vs_2_0 FireRingVS();pixelShader = compile ps_2_0 FireRingPS();PointSpriteEnable = true ;AlphaBlendEnable = true ;SrcBlend = One ;DestBlend = One ;ZWriteEnable = false ;}
}

这个粒子的效果例如以下截图:

略微改下。还能实现这种效果:

粒子系统的关键就在与怎样控制粒子的产生,运动等等。通过控制这些,你可以实现不论什么你想要的效果。

行,这是今天结束。

版权声明:本文博客原创文章,博客,未经同意,不得转载。

转载于:https://www.cnblogs.com/mengfanrong/p/4658597.html

DirectX (13) 粒子系统相关推荐

  1. UNITY 5.4.0发行说明中文版(不包含bug修正部分)

    原文地址:https://unity3d.com/cn/unity/whats-new/unity-5.4.0 Unity5.4.0F3 发行说明中文版(不包含bug修正部分) 因为工作需要自己临时翻 ...

  2. 网络游戏:为什么失败

    网络游戏:为什么失败 继互联网.电子商务.软件培训后,网络游戏是又一个被炒得过热的领域.随着钞票疯狂的砸下来,血拼的优胜劣汰进程也就开始了,如果不能走向成熟,就会走向失败. 开始的时候依靠的是概念和狂 ...

  3. U3D -- 一些知识点和优秀博客收藏

    1. 场景与工程 Project(工程)与Scene(场景)是不同的概念,一个项目工程可包含多个场景,而每个场景是唯一的.例如通关游戏,项目就是整个游戏,场景就是游戏中的各个关卡. 2. 图层的个数 ...

  4. mahout安装测试

    Mahout 是 Apache Software Foundation(ASF) 旗下的一个开源项目,提供一些可扩展的机器学习领域经典算法的实现,旨在帮助开发人员更加方便快捷地创建智能应用程序.Apa ...

  5. DirectX学习笔记(十五):粒子系统实现

    本系列文章由zhmxy555(毛星云)编写,转载请注明出处.   文章链接:http://blog.csdn.net/zhmxy555/article/details/8744805 作者:毛星云(浅 ...

  6. DirectX 3D_基础之粒子系统 广告牌技术 粒子和点精灵 点精灵的结构 点精灵的绘制状态 粒子及其属性

    每日一语: 写了一段时间的技术博客后,现在回到家里,打开电脑,不写点东西,好像浑身不自在一样.可能已经形成了习惯. 之前在一本书中看过,称为21天现象.就是说,如果你做一件事情,连续保持21天都在做这 ...

  7. 【Visual C++】游戏开发笔记四十三 浅墨DirectX教程十一 为三维世界添彩:纹理映射技术(二)...

    本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 作者:毛星云(浅墨)    邮箱: happylifemxy@163.com 本篇文章里,我们首先对Direct3D之中固定功能流水线中的 ...

  8. 动画骨骼【Visual C++】游戏开发五十二 浅墨DirectX教程二十 骨骼动画来袭(一)...

    间时紧张,先记一笔,后续优化与完善. 本系列文章由zhmxy555(毛星云)编写,载转请注明出处. 文章链接: http://blog.csdn.net/zhmxy555/article/detail ...

  9. 【Visual C++】游戏开发五十二 浅墨DirectX教程二十 骨骼动画来袭(一)

    这是答应大家的讲解骨骼动画的文章的N部曲的第二篇.这篇文章里,我们对现行的三种模型动画技术进行了概述,然后对X文件构成进行了详细的剖析,最后放出了骨骼动画的第一个示例程序,载入了<诛仙>中 ...

最新文章

  1. java线程触发_java线程
  2. python写一个文件下载器_Python3使用TCP编写一个简易的文件下载器
  3. 用户故事为什么要关联开发数据?
  4. Contiki Process概述
  5. python中字母大小顺序,如何在Python中按字母顺序对unicode字符串排序?
  6. springboot版本升级导致webservice调用失败org.apache.cxf.common.jaxb.JAXBUtils.createMininumEscapeHandle
  7. android小程序_小程序踩坑记
  8. 总结-linux初识进程(包括cpu调度、进程创建、僵尸进程(重点)、环境变量)
  9. 微商人赚钱的4个落地动作
  10. Mobile端Catalog下面Category的配置步骤
  11. 概率论——马尔科夫链
  12. 审阅模式中word保存不了
  13. 谷歌扩展程序设置ajax请求允许跨域(极少人知道的解决方案)
  14. oracle的权限授予,在Oracle模式上授予用户所有权限
  15. 谷歌Coral USB加速器
  16. 大数据到底是干什么用的?
  17. Chrome for Mac(谷歌浏览器MAC版)提示您的连接不是私密连接,没有继续访问选项解决方法
  18. 淘宝技术发展之路(本人强烈推荐)
  19. 【弄nèng - Activiti6】Activiti6应用篇之模型管理
  20. 2011年5月20日

热门文章

  1. filazilla搭建ftp_使用Filezilla搭建FTP服务器
  2. git stash暂存命令
  3. android+获取图库图片+4.4,Android 从 Android 本地图库选择多个图片
  4. esxi虚拟机的显卡怎么来的_远程映射图形界面,登录ESXI后台管理,更加方便操作...
  5. 证书 vivo_vivo秦飞:真假5G不存在 NSA模式手机未来仍可用
  6. python入门--动态绑定属性和方法
  7. 设计模式—单例模式(思维导图)
  8. 计算机组成原理—Cache写策略
  9. Linux和windows下多线程的区别
  10. 子矩阵最大累加和(详解)