Grafica 2D: perché usare gli spritesheets?


62

Ho visto molti esempi di come rendere gli sprite da un foglio di calcolo ma non ho capito perché sia ​​il modo più comune di gestire gli sprite nei giochi 2D.

Ho iniziato con il rendering 2d sprite nelle poche applicazioni demo che ho realizzato trattando ogni fotogramma di animazione per ogni tipo di sprite come trama propria - e questa raccolta di trame è memorizzata in un dizionario. Questo sembra funzionare per me e si adatta abbastanza bene al mio flusso di lavoro, poiché tendo a rendere le mie animazioni come file gif / mng e quindi estrarre i frame in singoli png.

C'è un notevole vantaggio prestazionale nel rendering da un singolo foglio piuttosto che da singole trame? Con l'hardware moderno in grado di attirare milioni di poligoni sullo schermo cento volte al secondo, importa anche per i miei giochi 2D che hanno a che fare con poche decine di rettangoli 50x100px?

I dettagli di implementazione del caricamento di una trama nella memoria grafica e della sua visualizzazione in XNA sembrano piuttosto astratti. Tutto quello che so è che le trame sono legate al dispositivo grafico quando vengono caricate, quindi durante il ciclo di gioco, le trame vengono renderizzate in batch. Quindi non mi è chiaro se la mia scelta influenzi le prestazioni.

Ho il sospetto che ci siano alcune ottime ragioni per cui la maggior parte degli sviluppatori di giochi in 2D sembrano usarli, non capisco perché.


No, non importa davvero troppo per i tuoi 50 sprite dispari. Ma cosa perdere?
Il comunista Duck il

Risposte:


69

Un argomento forte per l'utilizzo di fogli di calcolo è che il numero di trame disponibili su una scheda grafica può essere limitato. Pertanto, la tua libreria grafica dovrebbe costantemente rimuovere la trama e riassegnare le trame sulla GPU. È molto più efficiente allocare una texture di grandi dimensioni una sola volta.

Considera anche che le dimensioni delle trame sono in genere di potenza 2. Quindi, se hai uno Sprite 50x100px, assegnerai trame con le dimensioni 64x128px o nel peggiore dei casi 128x128px. Questo è solo uno spreco di memoria grafica. Prepara meglio tutti gli sprite in una trama di 1024x1024px, che consentirebbe sprite di 20x10 e perderai solo 24 pixel in orizzontale e in verticale. A volte anche gli sprite di diverse dimensioni vengono combinati in un unico enorme foglio di sprite per utilizzare la trama nel modo più efficiente possibile.

Addendum: un motivo molto importante per usare i fogli sprite è ridurre la quantità di call call sulla tua GPU, che può avere un notevole impatto sulle prestazioni. Ciò è stato affermato in altre risposte e lo sto aggiungendo per completezza, in modo da ottenere maggiore visibilità.


1
Grazie, non avevo preso in considerazione nessuno di questi punti - Sai approssimativamente qual è il limite al numero di trame disponibili? Non ho mai visto questa statistica menzionata nelle specifiche grafiche: il limite è sostanzialmente uguale alla quantità di RAM grafica?
Columbo,

Di solito il limite sarebbe la memoria GPU, sì. Ho pensato che ci fossero alcune restrizioni sul numero di trame sulle carte più vecchie, ma non riesco a trovare un riferimento che provi quel punto.
Bummzack,

12
Anche se non c'è un limite alla quantità, il traffico di autobus per lo spostamento di molte piccole immagini non è efficiente come uno (o alcuni) grandi trasferimenti.
Mordachai,

5
Aspetti positivi, ma l'aspetto più importante è ridurre al minimo le bancarelle della pipeline mantenendo il conto alla rovescia della chiamata di estrazione. Le GPU preferiscono una piccola quantità di lavori di grandi dimensioni, piuttosto che una grande quantità di piccoli lavori. Mettere tutti i tuoi sprite in una piccola quantità di fogli di grandi dimensioni significa che puoi impostare lo stage di testo una volta sola e disegnare un sacco di spite contemporaneamente in un batch. Spritebatch fa questo per te. Se hai più di un foglio di calcolo, assicurati di dire a spritebatch di ordinare in base alla trama
Cubed2D

L'aggiunta della compressione delle trame trasformerebbe qualsiasi spazio lento in una piccolissima quantità di sovraccarico, oltre a tutto ciò
Joe Plante

36

Direi che l'argomentazione da usare sarebbe la capacità di rendere più cose in una singola chiamata. Prendiamo ad esempio il rendering dei caratteri, senza uno spritesheet dovresti renderizzare ogni personaggio con uno scambio di trama separato seguito da una chiamata di disegno. Gettali in un foglio di calcolo e puoi eseguire il rendering di intere frasi con una singola chiamata di disegno (i caratteri di differenza nel carattere vengono selezionati semplicemente specificando i diversi raggi UV per gli angoli). Questo è un modo molto più efficiente di rendering quando un overhead molto reale del rendering di roba su molte piattaforme sta nel fare troppe chiamate API.

Può anche aiutare a risparmiare spazio, ma dipende in primo luogo dall'imballaggio nello spritesheet.


2
+1 Tocca su richiama chiamate. (qualcosa che non ho visto nella risposta accettata)
Michael Coleman,

11

Ogni chiamata di sorteggio ha una certa quantità di spese generali. Usando i fogli sprite puoi raggruppare il disegno di cose che non usano lo stesso frame di un'animazione (o più in generale, tutto ciò che è sullo stesso materiale) migliorando notevolmente le prestazioni. Questo potrebbe non importare troppo per i PC moderni a seconda del tuo gioco, ma sicuramente conta, ad esempio, sull'iPhone.


2
Sicuramente conta ancora. L'hardware grafico è stato ottimizzato per spingere tonnellate di poligoni per un piccolo numero di modelli dettagliati (es. Personaggi) perché la maggior parte dei giochi tende in quella direzione. Il risultato è che devi spingere il maggior numero possibile di poligoni in ognuna delle due dozzine di chiamate di disegno. I motori di gioco che rendono grandi scene come le città spesso combinano più trame in una al volo per ridurre le chiamate di disegno.
jhocking

Mi chiedo sicuramente se la texture u, v mapping in un sacco di hardware 3D, oltre a operazioni di blitting bit, tragga vantaggio dal foglio sprite.
Joe Plante,

7

Oltre alle considerazioni sulle prestazioni, i fogli sprite possono essere utili quando si crea l'arte; ogni personaggio può trovarsi nel suo foglio e puoi vedere tutti i fotogrammi semplicemente scorrendo. Mi aiuta a mantenere uno sguardo coerente su tutti i frame.

Inoltre, codice in AS3 e ogni file di immagine richiede un'istruzione di incorporamento separata. Preferirei avere un singolo embed di un intero foglio di calcolo piuttosto che 24 embed per tutti i frame, anche se sto usando una classe di risorse separata.


1
+1. Sebbene l'OP non stia utilizzando Flash, l'incorporamento o il caricamento è anche un punto a favore degli spritesheets. È anche rilevante quando le risorse vengono caricate da un server Web in cui 1 richiesta è preferita su diverse centinaia di richieste (per ogni "frame").
Bummzack,

Sicuramente vuoi ridurre le richieste del server per un gioco online. Abbiamo considerato se è meglio inserire le immagini in un .swf o in un foglio di calcolo perché entrambi raggiungono questo obiettivo principale (alla fine abbiamo deciso che i fogli di calcolo sono meno laboriosi per i nostri artisti).
jhocking del

7

Un altro motivo per cui utilizzare i fogli di calcolo con XNA è che con lo sviluppo di Xbox360 c'è un problema noto con tempi di distribuzione / caricamento lenti in relazione al numero di file presenti nel progetto. Quindi, combinando molti piccoli file di immagine in un singolo file di immagine, si potrà combattere questo problema.


5

Non ho intenzione di menzionare memoria / GPU qui, poiché ci sono abbastanza risposte del genere.

Invece, può chiarire la tua arte mentre ci lavori - e dopo. Invece di dover sfogliare 10 immagini per vedere il ciclo di camminata, puoi vedere tutti i fotogrammi in una volta sola. Se vuoi distribuire questo, hai solo 1 file da gestire invece di 10.

E poi è anche più pulito (dal punto di vista organizzativo) avere character.png e nemici.png su characterwalk01 fino a characterwalk10, quindi characterattack01 su characterattack05, e continua.


4

La memoria grafica non ha una gestione gonfia della memoria come i file system sui dischi; l'opposto è il caso: è mantenuto semplice e veloce .

Una gestione della memoria così semplice e veloce potrebbe essere come avere un solo sprite gigante 4096x4096 che viene tagliato in più folletti più piccoli dimezzandone la larghezza e / o l'altezza. (Esiste una simile tecnica di gestione della memoria monodimensionale, ma ho dimenticato il nome.) Alla fine, la deframmentazione deve essere eseguita.

Per saltare tale gestione della memoria in fase di esecuzione , gli sviluppatori riempiono automaticamente singoli sprite di grandi dimensioni con più sprite più piccoli in fase di compilazione o anche durante il processo di progettazione della grafica.


3

Inoltre, non dimenticare le operazioni di I / O che potrebbero salvarti durante l'inizializzazione. Se si sta caricando da un'unità CD, ogni file è una chiamata I / O aggiuntiva e potrebbe richiedere del tempo per la ricerca (i moderni HDD sono circa 15 ms per file, i CD forse 50-100ms?). Ciò può farti risparmiare un sacco di tempo di inizializzazione poiché è necessario recuperare solo un file. Inoltre, consente al tuo sistema operativo di memorizzare nella cache queste operazioni di I / O, nel caso l'applicazione stia facendo qualcos'altro (come aspettare la GPU).


1
Dall'altro lato, se si desidera risolvere il problema di ricerca dei file, è possibile raggruppare tutti gli sprite in un singolo file, utilizzando un formato personalizzato. La maggior parte dei giochi lo fa.
Tigrou,

0

Oltre ad essere più efficiente in termini di prestazioni, lo trovo semplicemente più semplice. Richiede un po 'di lavoro extra per assicurarsi che le tue immagini siano sempre entro i loro limiti quando si crea l'arte, ma è molto più facile riuscire a vedere tutte le immagini con cui hai a che fare al momento.

È anche più facile da programmare, secondo me. Ho semplicemente una serie di oggetti come:

sheet = {
    img: (the actual image),
    rects: [
        {x:0, y:0, w:32, h:32},
        {x:32, y:0, w:32, h:32},
        {x:64, y:0, w:32, h:32}
    ]
};

sheets.push(sheet);

Quindi per ogni articolo gli do due valori, foglio e rettangolo. Il foglio sarebbe l'indice nella matrice di oggetti e il rettangolo sarebbe l'indice nella matrice rects di quel foglio.

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.