Home Page Home Page Articoli Particle System

Particle System

Brevi cenni su come implementare un particle system in DirectX
Autore: Stefano Cristiano Livello:
Una delle tante applicazioni del texture blending è la creazione dei cosiddetti “sistemi particellari”. I particle system sono semplicissimi da implementare ma allo stesso tempo hanno un gradevolissimo impatto grafico. Potrei esordire con delle lunghe dissertazioni sui sistemi “fuzzy” e cose del genere, ma ho deciso di dare un taglio molto pratico a quest’argomento.

Cominciamo col dire che una particella non è altro che un punto nello spazio (2D o 3D, è lo stesso) che ha alcune proprietà tra le quali un “ciclo di vita”: nasce, si sviluppa e, come è naturale che sia, muore. Una particella appartiene ad un “sistema” di altre particelle ed obbedisce a determinate “leggi” imposte da tale sistema: potremmo chiamarle le “regole del gioco”. Una particella può interagire con altre particelle ma può anche ignorarne l’esistenza. Potremmo per esempio usare le particelle per simulare un corpo rigido, imponendo a tutte le particelle la contemporanea osservanza delle leggi della gravità (potremmo pensare ogni particella come un punto materiale) e dei cosiddetti vincoli di rigidità, dove ogni particella è costretta a mantenersi a distanza fissata da tutte le altre.

Potremmo descrivere tantissime altre applicazioni dei particle system, ma non basterebbe una vita. Focalizziamo quindi la nostra attenzione sui particle system “classici”, quelli che sono utilizzati da gran parte dei giochi in circolazione. Con questo tipo di particle system possiamo abbastanza facilmente simulare effetti tipo fontane, fuochi, colonne di fumo etc.

Ogni particella ha tra le sue proprietà principali almeno la posizione, la velocità, la dimensione ed un colore assocuiato, insomma è fatta a questa maniera:


struct SimpleParticle
{
D3DXVECTOR3 pos;
D3DXVECTOR3 vel;
float size;
DWORD color;
DWORD life;
};


Il particle “manager” che gestisce tutte le singole particelle, provvederà ad aggiornare/animare nel tempo le proprietà di ogni singola particella. Per esempio potremmo animare il colore, facendo in modo che partendo da un colore qualsiasi “random”, la particella sfumi quando sta per “morire” (variabile life<=0), modificando ad ogni frame il suo canale alpha (trasparenza). In questo modo si avrebbe l’effetto della particella che “perde energia” man mano che il suo ciclo vitale sta per terminare. Lo stesso discorso può valere per le dimensioni della particella, facendo in modo che sembri “consumarsi” nel tempo, facendo tendere la sua dimensione a zero.

L’esempio “Particles_1” fa queste cose animando solamente un parametro (la posizione) ed assegnando valori a casaccio al colore e alla dimensione.


bool FillParticles()
{
particles.clear();
D3DXVECTOR3 zero(0,0,0);
for(int i = 0; i < 50; i++)
particles.push_back(SimpleParticle(zero,RandVect(),RandSize(),RandColor()));

return true;
}

bool OnAnimate()
{
for(int i = 0; i < particles.size(); i++)
particles.pos+=particles.vel*wrapper->fElapsedTime;

static float lastfTime=wrapper->fTime;
//Ogni 1,5 secondi resettiamo...
if((wrapper->fTime-lastfTime)>1.5f)
{
lastfTime = wrapper->fTime;
FillParticles();
}
return true;
}

bool OnDraw()
{

unsigned int fv;
MyVertex* vertices = vb->Lock(6*particles.size(),fv);

if(!vertices)
return false;

for(int i = 0; i < particles.size(); i++)
{

D3DXVECTOR3 pos = particles.pos;
float hsize = particles.size/2.0f;
DWORD color = particles.color;
vertices[0]=MyVertex( pos+D3DXVECTOR3(-hsize,-hsize,0),
D3DXVECTOR2(0,0),color);
vertices[1]=MyVertex( pos+D3DXVECTOR3(-hsize,+hsize,0),
D3DXVECTOR2(0,1),color);
vertices[2]=MyVertex( pos+D3DXVECTOR3(+hsize,+hsize,0),
D3DXVECTOR2(1,1),color);
vertices[3]=MyVertex( pos+D3DXVECTOR3(+hsize,+hsize,0),
D3DXVECTOR2(1,1),color);
vertices[4]=MyVertex( pos+D3DXVECTOR3(+hsize,-hsize,0),
D3DXVECTOR2(1,0),color);
vertices[5]=MyVertex( pos+D3DXVECTOR3(-hsize,-hsize,0),
D3DXVECTOR2(0,0),color);
vertices+=6;
}

vb->Unlock();
LPDIRECT3DDEVICE8 lpDev=GetDevice();
lpDev->SetTexture(0,lpTex);
lpDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
lpDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
lpDev->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ONE);
lpDev->SetRenderState(D3DRS_LIGHTING,FALSE);
lpDev->SetRenderState(D3DRS_ZENABLE, TRUE);
lpDev->SetRenderState(D3DRS_ZWRITEENABLE,FALSE);
lpDev->SetStreamSource(0,vb->GetInterface(),sizeof(MyVertex));
lpDev->SetVertexShader(MyVertex_FVF);
lpDev->DrawPrimitive(D3DPT_TRIANGLELIST,fv,particles.size()*2);
lpDev->SetRenderState(D3DRS_ZWRITEENABLE,TRUE);
return true;
}


Come potete ben vedere in OnAnimate() utilizziamo la semplicissima legge del moto rettilineo uniforme. Utilizziamo però questa legge in versione infinitesima dato che integriamo incrementalmente la posizione con la velocità istantanea, data dalla velocità per wrapper->fElapsedTime che sta per il “dt” di tutti i vostri libri di fisica/analisi). La velocità dà sostanzialmente la direzione dello spostamento in questo caso, mentre il modulo è dato dal “dt”, e questo ci va benissimo per temporizzare il nostro particle system su macchine diverse. Questo “dt” è di solito chiamato in gergo “time step”.

Per il disegno delle particelle (alle quali associamo una texture) utilizziamo due triangoli che hanno un lato in comune. Non abbiamo ancora parlato di TRIANGLE ma per ora prendete per buono il fatto che stiamo semplicemente riempiendo un vertex buffer con tanti triangoli, a due a due disposti per formare dei quadrati. Per ogni triangolo specifichiamo tutte le tre coordinate (6 vertici per particella in totale). Dopo aver fatto questo, disegnamo con DrawPrimitive(…) tutti questi triangoli (che sono in numero uguale al numero di particelle per due, dato che ne servono appunto due per ogni particella).

Scriviamo la posizione del vertice, la coordinata texture ed il suo colore. Da notare che da come specifichiamo tali posizioni, la particella sarà centrata all’interno del quadrato formato dai due triangoli.

I flag che impostiamo sono quelli per il multipassing, dato che vogliamo far “fondere” tutte queste particelle tra loro, disabilitiamo l’illuminazione (potrebbe falsare i colori delle particelle) e disabilitiamo lo Zwrite (putroppo anche questo argomento è rimandato al capitolo sul 3D).

Il “grosso” del nostro particle system è sostanzialmente questo. Particle system più avanzati non fanno altro che aggiungere altre proprietà e le animano in maniera opportuna, ma la sostanza del loro funzionamento è la stessa.

Giusto per far capire che esistono anche altri tipi di particle system, ho creato l’esempio “Particles_2” dove le posizioni iniziali delle particelle vengono prese leggendo i vertici di una mesh tridimensionale in formato .x.
Voto medio articolo: 4.9 Numero Voti: 7
Stefano Cristiano

Stefano Cristiano

3D Coder. Sto lavorando ad un engine chiamato "Muse Engine" di cui potete leggere al mio sito http://pagghiu.gameprog.it Profilo completo

Articoli collegati

Integrare le Direct3D 8.1 con MFC Usando Visual Studio 6.0
In questo articolo mostreremo come creare una semplice applicazione SDI (Single Document Interface), in cui mostrare un oggetto tridimensionale in formato *.X e di farlo ruotare intorno all'asse Y.
Autore: Biagio Iannuzzi | Difficoltà:
Texture Blending (Parte II) Quake 3 Arena Shader System
Questo articolo è simile alla Parte I e ripete molti aspetti però tratta anche un pò degli shaders di Quake 3 Arena.
Autore: Stefano Cristiano | Difficoltà: | Voto:
Texture Blending (Parte I)
Come gestire gli effetti di blending tra texture. Multitexturing e Multipassing. Effect Files
Autore: Stefano Cristiano | Difficoltà: | Voto:
Sprite
Come creare uno "sprite" e animarlo. Special thanks to Elevator2 per gli sprites di megaman
Autore: Stefano Cristiano | Difficoltà: | Voto:
Texture
Introduzione al concetto di texture, di coordinate texture. Come animare le coordinate texture
Autore: Stefano Cristiano | Difficoltà:
Grafica 2D in DirectX. Vertex Buffers
Introduzione alla grafica 2D. Utilizzo dei vertex buffers
Autore: Stefano Cristiano | Difficoltà: | Voto:
Debbugging di applicazioni DirectX
Consigli e strategie per il Debugging delle applicazioni DirectX.
Autore: Stefano Cristiano | Difficoltà: | Voto:
Framework DXGWrapper
Spiega la filosofia di fondo del framework ideato dal sottoscritto ed usato da tutti i samples degli articoli relativi a DirectX.
Autore: Stefano Cristiano | Difficoltà: | Voto:
Gamma Correction e Colori
Una trattazione breve ma con una base matematica che spiega in parole povere il problema del fattore gamma e i colori in generale
Autore: Stefano Cristiano | Difficoltà: | Voto:
Inizializzazione e schermo
Si parla dell'inizializzazione dello schermo e delle modalità video in DirectX e di come gestire gli eventi "lost device", come scrivere un Game Loop e alcune info sul VSYNC
Autore: Stefano Cristiano | Difficoltà: | Commenti: 1 | Voto:
Introduzione a DirectX
Introduzione al mondo DirectX , requisiti, tools necessari, configurazione dell’ambiente di sviluppo.
Autore: Stefano Cristiano | Difficoltà: | Commenti: 2 | Voto:
Copyright © dotNetHell.it 2002-2017
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5