2010-06-28 18 views
6

tempo per un'altra domanda XNA. Questa volta è puramente dal punto di vista del design tecnico.XNA - Creazione di un sacco di particelle allo stesso tempo

La mia situazione è questa: Ho creato un motore di particelle basato su calcoli GPU, lungi dall'essere completo ma funziona. La mia GPU gestisce facilmente particelle da 10k senza sudare e non sarei sorpreso se potessi aggiungerne un altro.

Il mio problema: Ogni volta che ho un sacco di particelle create allo stesso tempo, il mio frame rate mi odia. Perché? Un sacco di utilizzo della CPU, anche se l'ho ridotto al minimo per contenere quasi solo le operazioni di memoria.

creazione di particelle viene ancora fatta a CPU-chiamate quali:

  • Metodo vuole creare particelle ed effettua una chiamata.
  • Quad nasce in forma di vertici e memorizzati in un buffer
  • tampone è inserito nella GPU e la CPU può concentrarsi su altre cose

Quando ho circa 4 emettitori creando una particella per fotogramma, mio FPS abbassa (certo, solo 4 fotogrammi al secondo, ma 15 emettitori fanno cadere il mio FPS a 25).

Creazione di una particella:

 //### As you can see, not a lot of action here. ### 
     ParticleVertex []tmpVertices = ParticleQuad.Vertices(Position,Velocity,this.TimeAlive); 
     particleVertices[i] = tmpVertices[0]; 
     particleVertices[i + 1] = tmpVertices[1]; 
     particleVertices[i + 2] = tmpVertices[2]; 
     particleVertices[i + 3] = tmpVertices[3]; 
     particleVertices[i + 4] = tmpVertices[4]; 
     particleVertices[i + 5] = tmpVertices[5]; 

     particleVertexBuffer.SetData(particleVertices); 

miei pensieri sono che forse non dovrei creare particelle che spesso, forse c'è un modo per lasciare la GPU di creare tutto, o forse sono io che don' So come fai queste cose. ;)

Modifica: Se non dovessi creare particelle che spesso, qual è la soluzione per farlo sembrare ancora buono?

Quindi sto postando qui nella speranza che tu sappia come un buon motore di particelle dovrebbe essere progettato e se forse ho preso la strada sbagliata da qualche parte.

risposta

4

Non c'è modo di fare in modo che la GPU crei tutto (con l'uso di Geometry Shaders che richiede SM4.0).

Se stessi creando un sistema di particelle per la massima efficienza CPU, avrei pre-creare (solo per prendere un numero per fare un esempio) 100 particelle in un buffer vertice e indice come questo:

  • Crea un buffer vertice contenente quad (quattro vertici per particella, non sei come hai)
  • Usa un formato di vertice personalizzato che può memorizzare un valore di "offset di tempo", nonché un valore di "velocità iniziale" (simile al XNA Particle 3D Sample)
  • Impostare il valore di tempo in modo che ogni parte icle ha un offset di tempo di 1/100 in meno rispetto all'ultima (quindi gli offset vanno da 1,0 a 0,01 attraverso il buffer).
  • Imposta la velocità iniziale in modo casuale.
  • Utilizzare un buffer indice che fornisce i due triangoli necessari utilizzando i quattro vertici per ogni particella.

E la cosa bella è che devi farlo solo una volta - puoi riutilizzare lo stesso buffer di vertici e buffer di indice per tutti i tuoi sistemi di particelle (a condizione che siano abbastanza grandi per il tuo sistema di particelle più grande).

Poi avrei un vertex shader che avrebbe preso il seguente testo:

  • Per-Vertex: Offset
    • Tempo
    • velocità iniziale
  • Shader Parametri:
    • ora
    • particelle vita (che è anche il tempo particella avvolgente valore, e la frazione di particelle nel buffer in uso)
    • posizione Il sistema di particelle/rotazione/scala (matrice mondo)
    • Eventuali altri ingressi interessanti che gradite, quali: dimensione delle particelle, la gravità, vento, ecc
    • una scala temporale (per ottenere un tempo reale, così velocità e altri calcoli fisici senso)

Tale vertex shader (di nuovo come XNA Particle 3D Sample) poteva quindi determinare la posizione del vertice di una particella in base alla sua velocità iniziale e il tempo in cui quella particella era stata nella simulazione.

Il tempo per ogni particella sarebbe (pseudo codice):

time = (currentTime + timeOffset) % particleLifetime; 

In altre parole, come il tempo avanza, particelle sarà rilasciato ad una velocità costante (dovuto alla distanza). E ogni volta che una particella muore a time = particleLifetime(o è a 1.0? Il modulo a virgola mobile confonde), i cicli temporali tornano a time = 0.0 in modo che la particella rientri nell'animazione.

Quindi, quando è arrivato il momento di disegnare le mie particelle, avrei impostato i parametri buffer, shader e shader e chiamato DrawIndexedPrimitives. Ora ecco un piccolo consiglio: impostare startIndex e primitiveCount in modo tale che nessuna particella inizi a metà dell'animazione. Quando il sistema di particelle inizia per la prima volta, estraggo 1 particella (2 primitive) e nel momento in cui la particella sta per morire, disegnerei tutte le 100 particelle, la cui 100 sarebbe appena iniziata.

Quindi, un attimo dopo, il timer della 1a particella si arrotolava intorno e lo trasformava nella 101 ° particella.

(Se avessi voluto solo 50 particelle nel mio sistema, avevo appena impostato la mia vita di particelle a 0.5 e sempre e solo trarre le prime 50 delle 100 particelle nel vertex buffer/index.)

E quando è arrivato il momento di spegnere il sistema di particelle - basta fare lo stesso in senso inverso - impostare startIndex e primitiveCount in modo che le particelle smettono di essere disegnate dopo la morte.

Ora devo ammettere che ho sorvolato la matematica in questione e alcuni dettagli sull'utilizzo di quad per particelle - ma non dovrebbe essere troppo difficile da capire. Il principio di base per capire è che stai trattando il tuo vertice/indice di buffer come un buffer circolare di particelle.

Uno svantaggio di un buffer circolare è che, quando si interrompe emettendo particelle, a meno che si arresta quando l'ora attuale è un multiplo della durata particella, si finisce con il set attivo di particelle a cavallo delle estremità della buffer con un gap nel mezzo - quindi richiede due richiami di draw (un po 'più lento). Per evitare ciò, è possibile attendere fino al momento giusto prima di fermarsi, per la maggior parte dei sistemi questo dovrebbe essere ok, ma potrebbe sembrare strano per alcuni (ad esempio: un sistema di particelle "lento" che deve fermarsi immediatamente).

Un altro aspetto negativo di questo metodo è che le particelle devono essere rilasciate a una velocità costante, anche se questo è solitamente piuttosto tipico per i sistemi di particelle (ovviamente questo è per sistema e la velocità è regolabile). Con un piccolo ritocco dovrebbe essere possibile un effetto di esplosione (tutte le particelle rilasciate contemporaneamente).

Tutto ciò che viene detto: se possibile, può essere utile utilizzare una libreria di particelle esistente.

Problemi correlati