Per il rendering voxel, cosa è più efficiente: VBO pre-made o uno shader di geometria?


26

Dato un array voxel abbastanza statico, ciò che è più efficiente: usare la CPU per pre-generare un VBO per renderizzare le facce voxel (ignorando per ora forme più avanzate di rendering come cubi in marcia) o usare uno shader di geometria sulla GPU per generare il facce al volo?

Non sono così preoccupato di aggiornare i voxel cambiando, ma ovviamente questo è un vantaggio della versione GPU poiché non è necessario ricostruire i VBO. Inoltre, l'approccio GS sembra un po 'più moderno :)

D'altra parte, non ho esaminato i dettagli su come un GS funziona effettivamente con la pipeline di rasterizzazione nelle moderne GPU. Emette i vertici in una sorta di stream-cache o i vertici sono scritti nella normale memoria GPU nel mezzo? Se è quest'ultimo, quindi la generazione al volo potrebbe ridurre la larghezza di banda disponibile e la potenza di elaborazione dal resto delle attività della GPU immagino e quindi sarebbe più vantaggioso farlo sulla CPU.

Risposte:


9

Sto pensando a una scena di tipo Minecraft, dove per voxel intendi un mondo di blocchi che sono effettivamente resi usando poligoni:

Se usi uno shader di geometria, sarà difficile evitare di avere esattamente tre facce (o qualsiasi altra cosa) per voxel.

Se hai molti blocchi adiacenti che hanno la stessa trama, puoi usare la piastrellatura delle trame per avere molti meno triangoli nella tua striscia (degenerata) in un approccio VBO. Voglio dire, se c'è una bella grande area piatta 6x6 di voxel di erba, puoi disegnare l'intera cima in soli 2 triangoli anziché 64.

Con l'approccio GS non puoi fare il banale abbattimento di facce occluse da voxel adiacenti che è molto semplice anche con un approccio VBO.

Non ho provato l'approccio GS, ma posso dire che l'approccio VBO con la combinazione di ripetizioni di tessere adiacenti funziona molto bene. Ho trovato che scherzare con gli indici degli elementi è molto più lento della semplice ripetizione dei vertici. Se dividi il tuo mondo in piccoli cubetti, puoi in genere usare solo un byte per componente per vertice e persino impacchettare le informazioni sulla trama e le normali (una faccia su un cubo allineato all'asse ha solo 3 possibili normali) ecc. In un quarto byte per creare 4 byte per vertice che è bello e veloce.

Ho usato VBO separati per ognuna delle 6 facce - ovviamente devi solo disegnarne al massimo 3. Ciò si adatta perfettamente alle diverse trame normalmente utilizzate nelle parti superiori dei voxel in stile Minecraft. Perché per ogni set il normale e tale è quindi uniforme.

Con l'uso di pixmap piastrellate verticalmente in un atlante con GL_REPEATsull'asse orizzontale e avendo versioni ruotate di 90 gradi delle pixmap nello stesso atlante, ho scoperto che posso disegnare enormi quantità di blocchi apparentemente diversi usando lo stesso VBO nella stessa chiamata. Nell'esempio di area erbosa 6x6, l'avrei diviso in 12 triangoli poiché ho ripetuto solo una dimensione nel mio atlante.

Per lo più ho fatto in modo che funzionasse sull'estremità più bassa dei chip grafici e mobile integrati, dove GS è solo qualcosa su cui posso sognare di giocare un giorno.


3
Devi solo disegnare al massimo 3 facce per voxel, ma potresti dover disegnare facce diverse per ogni voxel a seconda del punto di vista, quindi l'ottimizzazione non è così facile, vero? Un VBO pre-creato conterrà più di un voxel. Se il tuo punto di vista si trova tra i voxel, vedrai il lato est dell'uno e il lato ovest dell'altro. L'unico modo in cui ciò potrebbe aiutare è che puoi eliminare banalmente le facce rivolte all'indietro, ma il caso peggiore è comunque rendere 5 di 6 lati in un gruppo di voxel. Se il tuo punto di vista è al di fuori dei limiti assiali del VBO, devi solo renderizzare 3 lati.
Bjorn Wesen,

Spot su Bjorn, è fattibile. (Ma sto creando VBO per blocchi come necessario e riconsiderando ciò che ho costruito quando la telecamera si muove, piuttosto che avere il mondo intero in VBO in ogni momento; quindi ho un momento naturale per fare queste scelte)
Will

10

Che dire della terza opzione, usando array istanziati? Fondamentalmente si disegnano molte caselle (fatte di un semplice cubo a 8 vertici) con una singola chiamata di disegno, ottenendo le posizioni (e altri dati) come attributi per istanza dal VBO voxel-data (usando glVertexAttribDivisorin OpenGL, sono sicuro DX ha anche quello). Questo potrebbe essere più veloce dell'approccio dello shader della geometria sebbene il codice dell'applicazione (non shader) dovrebbe essere abbastanza simile, poiché ricordo che gli shader della geometria hanno la reputazione di essere lenti, anche se non ho esperienza con loro (o istanza) mentre sono ancora seduto su hardware 2.1.

Tuttavia, sia gli shader di geometria che gli array istanziati dovrebbero essere più adatti della geometria voxel costruita dalla CPU, specialmente quando i dati voxel sono soggetti a modifiche. Insieme al feedback di trasformazione (output di flusso in DX?) Potresti essere in grado di impostare una buona tecnica di abbattimento basata su GPU.


Sì, questa è la migliore soluzione a questo problema. Perché non mi è successo? :)
Notabene,

Dopo un po 'di sperimentazione, devo dirti che la geometria cotta batte ogni istanza con un ampio margine. Non ho ancora provato gli shader di geometria.
Jari Komppa,

@JariKomppa puoi approfondire cosa intendi per geometria al forno?
Steven Lu,

Istanze pre-tradotte e copiate in una singola mesh. Come avere una maglia che rappresenta un centinaio di cubi o altro.
Jari Komppa,

@JariKomppa Ho visto gli stessi risultati, in cui la creazione della mesh è molto più veloce. Comunque su GTX 680 l'opzione di istanza sembra funzionare molto più velocemente, strana.
Levi H,

1

La versione di Geometry shader mi suona molto meglio. Puoi avere solo punto vbo e costruire la casella al volo (punto di input, flusso del triangolo di output). Sarà veloce (anche più veloce se userete unità di tassellatura nel modello shader 5 eq. DX11) e ridurrete estremamente la larghezza di banda, sarà una soluzione piacevole e pulita.

A proposito di GS. Viene messo tra shader di vertici e pixel shader e modifica il flusso di vertici (primitivi) in uscita. Mentre lo shader di vertice funziona solo sui vertici, lo shader di geometria funziona su interi primitivi. L'output di questo flusso va solo al pixel shader (ed è rasterizzato prima di quello fuori rotta :)) e non c'è modo di salvarlo. (Forse da un pazzo rendering alla trama e poi analizzandolo ... ma nessuna possibilità reale reale)

Nota sulle prestazioni: dovresti essere in grado di eseguire tutte le operazioni nello shader della geometria e saltare lo shader di vertice. Ma non è il modo migliore. Meglio (più veloce) è fare la maggior parte delle possibili trasformazioni sul vertex shader e cercare di minimizzare il programma di shader della geometria. Non abbiate paura di usare per il ciclo se ne avrete bisogno (per esempio per la creazione di scatole). Il compilatore lo srotolerà per te.


2
Potrebbe essere una buona idea verificare la presenza di voxel adiacenti nella geometria e / o shader di vertice e scartare i vertici o saltare le facce se sono occluse. Altrimenti, la soluzione GS aumenterà invece la larghezza di banda utilizzata.
Tamschi,

Bandwith non sarà un grosso problema (dalle mie esperienze), ma ovviamente è vero. E non puoi cercare nelle altre primitive in GS (lo so :)).
Notabene,

@Tamschi: sì, questo problema si è verificato subito dopo aver scritto questa domanda .. per la versione CPU, i voxel nel mezzo dei solidi vengono eliminati, ma questo potrebbe essere impossibile sulla GPU senza un pre-passaggio con ciò che equivarrebbe a un differenziazione ..
Bjorn Wesen,

1
È possibile associare il buffer dei vertici a un'uniforme isamplerBuffer o usamplerBuffer nello shader, quindi eseguire ricerche con texture (nome_di_uniforme, indice). Un'altra opzione sarebbe quella di associare il buffer a un array uniforme, che ti dà più libertà in quale formato di vertice vuoi usare.
Tamschi,
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.