Il modo più veloce per creare un semplice effetto particellare


12

Sto cercando il modo più veloce per creare un effetto particellare davvero semplice che verrà spammato come l'inferno sul gioco ...

Fondamentalmente, il mio gioco sembra un gioco vectrex, fatto principalmente di linee ... Voglio fare alcune piccole esplosioni che saranno davvero comuni.

C'è qualcosa di più veloce del semplice spostamento di alcuni punti e del rendering con GL_Point?


+1 solo per il riferimento Vectrex. Ho trascorso alcune ore divertenti su Scramble e Tempest da bambino nei primi anni '80. Senza quello probabilmente non sarei finito come sviluppatore di giochi oggi.
Kylotan,

Sì, Tempest è eccezionale: D
speeder,

Come dico che nessuno è corretto?
speeder,

Risposte:


13

Non è necessario archiviare la memoria per ogni particella e animarla separatamente. Puoi farlo proceduralmente ricostruendo la posizione delle particelle durante il disegno usando la classica equazione fisica. s = ut + 1 / 2.at ^ 2

Un semplice esempio (senza costante accelerazione di particelle):


void drawExplosion(ExplosionParameters& s)
{
  Random rng;
  rng.seed(s.startSeed);
  glBegin(GL_POINTS);
  for (int i = 0; i < s.numParticles; i++)
  {
    vec3 vel = rng.getRandomVector(-1.0f, 1.0f) * s.explosionSpeed;
    float timeBias = rng.getRandom(0, s.particleTimeBias);
    vec3 pos = s.explosionCentre + (vel * (s.timeElapsed + timeBias));
    glPoint3fv(&pos);
  }
  glEnd();
}

Quindi semplicemente aumenti s.timeElapsed su ogni iterazione del tuo ciclo di aggiornamento.

È anche completamente suscettibile di essere implementato sulla GPU, liberando così la tua CPU dal dover fare qualsiasi lavoro. Un'implementazione di gpu potrebbe assomigliare a questa:

void drawExplosion(ExplosionParameters& s)
{
    //bind Vertex Shader If Not Already Bound();
    ...
    // bindVertexBuffer of Zeroes If Not AlreadyBound();
    glVertexPointer(...)
    //uploadShaderUniformsForExplosion(s);
    glUniform3f(...)
    ...
    glDrawArrays(GL_POINTS, 0, s.numParticles);
} 

Lo shader di vertice GPU ricostruirà quindi la posizione delle particelle tramite l'equazione fisica e le uniformi / costanti passate ad essa - proprio come faceva la versione CPU.

Per aggiungere una certa varianza, puoi usare più esplosioni simultanee con parametri leggermente diversi, animando colori / alfa, scegliendo diverse posizioni di partenza. eccetera.


Inoltre, è possibile utilizzare la prevedibilità di numeri pseudo casuali per generare tutti i vettori iniziali di tutte le particelle, creando centinaia di particelle da pochi dati int. L'uso della GPU per creare i quad è una buona idea per particelle semplici.
Skizz,

Per anni ho realizzato i sistemi di particelle nel modo tradizionale con array di classi che trattano le particelle come entità semi-intelligenti e mi è sempre sembrato un po 'dispendioso e gonfio. In questo modo è molto meglio per le particelle di base che non fanno altro che vomitare sullo schermo.
Piku,

7

Ho fatto diversi test e il modo PIÙ VELOCE (non il più veloce da codificare) erano le particelle fatte di GL_LINE che conoscevano la loro posizione e velocità, e le ho usate come punti durante il rendering (quindi, più veloce è la particella, più "linea" diventa, più lentamente diventa un punto).

L'effetto è DAVVERO fantastico (guarda qualsiasi video di guerre di geometria per vederlo), e VERAMENTE veloce. Elimina i quadricipiti (specialmente perché i quadricipiti mi farebbero calcolare la doppia quantità di vertici)

Inoltre, è meglio che usare un sistema particellare già fatto, perché volevo un effetto specifico e VELOCE, i sistemi particellari di solito supportano molte funzioni, con una quantità proporzionale di sovraccarico.


2
+1 per spiegare cosa hai finito per fare, anche se sarei curioso di conoscere maggiori dettagli sui tuoi test. =)
magro

Btw: Tutto ciò era in modalità immediata (questa è l'unica cosa che so come programmare, e ho imparato il nome ieri ...)
speeder

6

Normalmente penso che faresti particelle come quad-texture mappate. Trattali essenzialmente come sprite 2D e li dissolvono nel tempo, distruggendoli quando sono invisibili. Meglio ancora, riutilizzare quelli vecchi quando ne fai di nuovi in ​​modo da non distruggere la memoria per queste cose.

Se usi l' alfa premoltiplicata sull'arte, puoi facilmente supportare luci, fuoco, fumo e altro oltre a tutti con un tipo di operazione di fusione.


Hum ... i punti non sono più veloci delle trame?
speeder,

2
L'hardware grafico è specificamente ottimizzato per rasterizzare trame al framebuffer. Se i punti sono più veloci, è probabile che siano di un importo trascurabile e perdi tutte le possibilità che ottieni con la trama.
Kylotan,

tipo cosa? Intendiamoci, non sto realizzando un sistema particellare completo, è solo un effetto specifico (piccole esplosioni, soprattutto per il feedback di gioco che colpisci qualcosa)
Speeder,

Se vuoi solo usare punti o linee, allora va bene. Posso solo commentare ciò che la maggior parte delle persone fa per le particelle. Forse un triangolo non riempito sarebbe una bella particella.
Kylotan,

4

Con OpenGL ES 2.0, ES 1.X con estensione e OpenGL => 2.1, puoi utilizzare GL_POINT_SPRITES. GL_POINT_SPRITES sono come un quad sempre davanti alla telecamera.

In shader di frammenti, puoi:

  • definire le dimensioni di sprite con gl_PointSize nello shader di vertici
  • usa gl_PointCoord (coordinate uv) nello shader di frammenti

Puoi usare la trama con l'alfa per disegnare sprite a palla ...

Un tutorial per Point Sprites


Sto evitando le estensioni, quelle sciocche che il motore (che non ho fatto) già usano, sono abbastanza sufficienti per molte persone che si lamentano che il gioco non funziona ...
Speeder,

1

La maggior parte dei sistemi di effetti particellari che ho visto, invece di disegnare un numero enorme di punti, disegna un numero relativamente ridotto di trame di cartelloni pubblicitari in cui ogni trama assomiglia un po 'a un'esplosione. A meno che il tuo stile artistico non impedisca davvero, probabilmente sarai più felice di percorrere quella strada. Ridurrà al minimo la quantità di particelle necessarie per animare e renderizzare individualmente, pur offrendo un grande effetto visivo.


1
È vero, ma punta allo stile Vectrex, funzionerebbe meno bene lì.
Kaj,

1
Esattamente quello che ha detto Kaj ... sarebbe inutile, e aumenterebbe la dimensione del download (sto cambiando la maggior parte della grafica che posso da sprite a vettori reali, quindi posso ridurre la dimensione del file)
speeder

1

Per un piccolo modo pulito di gestire la generazione / cancellazione / aggiornamento di particelle, supponendo che tu abbia una semplice serie di particelle - Particelle [MAX_PARTICLES]:

Tieni traccia delle particelle attive (a partire da NumActiveParticles = 0)

Nuove particelle vengono sempre aggiunte alla fine dell'array:

pNewParticle = &Particles[NumActiveParticles++];

Il bit intelligente - Quando rimuovi una particella "morta" - scambiala con l'ultima particella attiva e decrementa NumActiveParticles:

if ( DeadParticle < NumActiveParticles-1 )
{
  Particles[ DeadParticle ] = Particles[ NumActiveParticles-1 ];
}
NumActiveParticles--;

Ciò evita qualsiasi ricerca di "particelle inutilizzate" durante la generazione, ed evita qualsiasi scansione attraverso una matrice di MAX_PARTICLES se nessuna è in uso.

Si noti che questo funziona solo se l'ordine di aggiornamento / rendering non è importante (come nel caso di molti effetti particellari, che utilizzano la fusione additiva) - poiché questo metodo di eliminazione di una particella riordina l'array


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.