È possibile costruire un cubo con meno di 24 vertici


14

Ho un mondo basato su cubi come Minecraft e mi chiedo se c'è un modo per costruire un cubo con meno di 24 vertici in modo da poter ridurre l'utilizzo della memoria.

Non mi sembra possibile per 2 motivi: le normali non uscivano bene e le trame faccia a faccia non funzionavano.

È questo il caso o sbaglio? Forse c'è qualche nuova fantastica tecnologia DX11 che può aiutarti?

Modifica: solo per chiarire, ho 2 requisiti: ho bisogno di normali di superficie per ogni faccia del cubo per fare l'illuminazione corretta e ho bisogno di un modo per indirizzare un indice diverso in un array di trama per ogni faccia del cubo


1
Vuoi ridurre l'utilizzo della memoria della scheda grafica o l' utilizzo della RAM ?
doppelgreener,

1
I dati del vertice sono archiviati nella RAM e nella GPU in questo momento, quindi ridurli ridurrebbe entrambi.
Telanor,

Risposte:


9

Se hai solo bisogno di normali per faccia e se i tuoi texcoords per una faccia sono rigorosamente 0/0, 0/1, 1/0, 1/1 (o simili per adattarsi al tuo layout), puoi costruire un cubo con 8 verts e 30 (striscia con riavvio) o 36 (elenco) indici. Recupera le normali e i texcoords usando una ricerca di array costante basata su SV_VertexID nel tuo vertex shader.

Ciò significa che non è nemmeno necessario includere texcoords o normali nel buffer dei vertici, il che consentirà di risparmiare ancora di più la memoria.

Andando oltre, potresti ancora andare fino a 24 verts per cubo ma usare anche l'istanziamento. Ogni cubo avrebbe una dimensione fissa nel buffer dei vertici (1x1x1) e avresti un fattore di scala e una posizione (supponendo che i cubi non ruotino, una matrice se lo fanno) come dati per istanza. Nel caso non rotante hai un costo una tantum di 24 verts, ma ogni cubo ha solo bisogno di 6 float per specificare completamente. Nel caso rotante stai guardando 16 float, ma anche questo è un notevole risparmio (in questo caso è più probabile che il collo di bottiglia sul lato CPU sulle trasformazioni della matrice - per il caso non rotante che costruisce una matrice al volo in il tuo shader di vertice - anche se è fatto per vertice, è così stupidamente veloce che non devi nemmeno preoccupartene).

Per trame faccia a faccia, basta usare un array di trame. È necessario assicurarsi che ciascuna di tali trame nell'array abbia le stesse dimensioni, ovviamente, e sarà comunque necessario interrompere il batch corrente se l'array stesso deve cambiare, ma per il resto farà bene il lavoro. Aggiungi un terzo texcoord alla definizione del vertice che definisce la porzione di array da utilizzare per ciascuna faccia.

Non hai bisogno di un GS con questo, e dovrebbe funzionare più velocemente dell'uso di uno poiché avere lo stadio shader della geometria abilitato imporrà un sovraccarico aggiuntivo di per sé.

Ho un codice di riferimento nel mio motore che disegna solo un sacco di cubi usando questo metodo e posso facilmente mordere oltre 300.000 cubi pur cancellando 60 fps, su una GPU relativamente di fascia bassa e senza fare nient'altro per ottimizzare il processo . Devo ammettere che non li sto illuminando né testurando, ma ho abilitato il blending alfa, l'abbattimento del backface disabilitato e, nel complesso, si equilibra con la mia parte "non fare altro per ottimizzare", quindi dovrebbe darti un'idea ragionevole del tipo di palla da baseball che puoi colpire con questo metodo.


1
Prima stavo usando l'istanziamento e funziona benissimo con cubetti sotto i 40k. Ma ho almeno 256k cubi e anche l'istanziamento non lo gestiva. L'uso di SV_VertexID con una ricerca sembra comunque molto promettente.
Telanor,

Quanto era grande il buffer per istanza? Cercare di inserirli tutti in un enorme buffer potrebbe finire per soffocare la tua GPU; In genere mantengo i buffer per istanza a sufficienza per 64k oggetti (suddividendo le chiamate di disegno se necessario), utilizzo il modello discard / no-overwrite e scrivo direttamente sul puntatore mappato invece di copiare da un array intermedio, che funziona molto bene .
Maximus Minimus,

Inoltre, è essenziale mantenere basso il numero di mappe. Mappare / scrivere un cubo / non mappare 40k volte sarà molto più lento di mappare / scrivere 40k cubi / unmap solo una volta. Se stavi facendo il primo, prova a passare al secondo.
Maximus Minimus,

15

Penso che l'ottimizzazione principale che puoi realizzare sia basata sul fatto che non tutti i cubi avranno effettivamente bisogno di tutti e 24 i vertici . In effetti, gli unici cubi che richiedono 24 vertici sono quelli che galleggiano a mezz'aria, il che è probabilmente un evento raro.

In generale, genera solo quadratini per i volti a contatto con l'aria . Ciò significa che se due cubi si toccano, non è necessario generare vertici per la faccia in cui si stanno toccando.

L'immagine sotto mostra questo concetto, ma in 2D per una più facile comprensione. Nell'immagine ci sono 11 blocchi occupati (rappresentati dai cerchi grigi pieni), che normalmente richiederebbero 4 x 11 = 44 bordi per rappresentare (4 perché è un quadrato, non un cubo). Ma come puoi vedere, devi solo disegnare i bordi quando sono in contatto con un quadrato vuoto, che in questo caso ha solo 8 bordi.

inserisci qui la descrizione dell'immagine

Se un esempio così semplice in 2D è riuscito a ridurre 44 bordi a 8 bordi, immagina i guadagni in un grande mondo 3D ...

Questo è l'approccio descritto in questo articolo , che ti consiglio di leggere, nonostante sia rivolto a OpenGL. I concetti dovrebbero essere piuttosto universali però.

Probabilmente potresti anche usare uno shader di geometria per generare i vertici al volo sulla GPU, eliminando la necessità di memorizzarli in memoria, ma non ho esperienza con questo, né so quanto bene si sarebbe comportato per un grande mondo.


1
Articolo molto interessante. Sto già facendo l'ottimizzazione dei bordi, che sicuramente aiuta molto. Proverò gli shader di geometria a vedere se funziona.
Telanor,

Vuoi dire, utilizzare lo shader della geometria e il prodotto incrociato per calcolare le normali? Stavo pensando di usarlo, come creare un programma separato per superfici piane (non mi occupo delle trame).
dreta,

@dreta Non solo, ma andando al punto in cui si inviano solo i centroidi del cubo come elenco di punti e tutti i vertici vengono emessi dal GS. Forse codificare alcune informazioni vicine nei punti in modo che lo shader generi solo le facce che sono davvero necessarie, anche se non ho pensato a come.
David Gouveia,

Se vuoi prestazioni, non usare uno shader di geometria ... Quasi mai. Hanno completamente rovinato la pipeline. Se vuoi generare geometria sulla GPU, usa uno shader di calcolo o openCL
Robert Fraser
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.