Voxel Face Crawling (semplificazione della mesh, possibilmente usando avidità)


9

Modifica: questo è solo per la mia esperienza di apprendimento, NON è per motivi di prestazioni che faccio questa domanda.

Questo è per quanto riguarda un motore di terreno simile a Minecraft. Conservo blocchi in blocchi (blocchi 16x256x16 in un blocco). Quando generi un pezzo, utilizzo più tecniche procedurali per impostare il terreno e posizionare gli oggetti. Durante la generazione, mantengo un array 1D per l'intero blocco (solido o no) e un array 1D separato di blocchi solidi.

Dopo la generazione, eseguo l'iterazione attraverso i blocchi solidi controllando i loro vicini in modo da generare solo facce di blocco che non hanno vicini solidi. Memorizzo le facce da generare nella loro lista (ovvero 6 liste, una per ogni faccia / normale). Quando eseguo il rendering di un blocco, eseguo il rendering di tutti gli elenchi del blocco corrente della videocamera e solo degli elenchi rivolti verso la videocamera in tutti gli altri blocchi. Faccio questo memorizzando tutte e 6 le liste in un buffer, quindi cambio semplicemente gli intervalli che disegno.

Usando un atlante 2D con questo piccolo trucco di shader suggerito da Andrew Russell, voglio unire facce simili completamente insieme. Cioè, se sono nella stessa lista (la stessa normale), sono adiacenti l'uno all'altro, hanno lo stesso livello di luce, ecc. So che finirò comunque con i rettangoli, ma dovrebbe ridurre facilmente il mio conteggio dei vertici del 50% o meglio se le mie stime sono corrette.

La mia ipotesi sarebbe quella di avere ciascuna delle 6 liste ordinate in base all'asse su cui poggiano, quindi in base agli altri due assi (l'elenco per la parte superiore di un blocco sarebbe ordinato in base al suo valore Y, quindi X, quindi Z).

Con questo da solo, potrei facilmente unire strisce di facce, ma sto cercando di unire più di semplici strisce quando possibile. Ho letto su questo avido algoritmo di meshing, ma ho molti problemi a capirlo.

Quindi, la mia domanda: per eseguire l'unione dei volti come descritto (ignorando se si tratta di una cattiva idea di terreno / illuminazione dinamica), esiste forse un algoritmo che è più semplice da implementare? Accetterei anche felicemente una risposta che mi guidi attraverso l'avido algoritmo in un modo molto più semplice (un link o una spiegazione).

Non mi dispiace un leggero calo delle prestazioni se è più facile da implementare o anche se è solo un po 'meglio che fare semplicemente strisce. Temo che la maggior parte degli algoritmi si concentri sui triangoli piuttosto che sui quad e usando un atlante 2D così come sono, non so che potrei implementare qualcosa di triangolare in base alle mie attuali competenze.

PS: ho già frustum cull per chunk e come descritto, ho anche abbattuto facce tra blocchi solidi. Non occloro ancora l'occlusione e forse mai.

* Modifica: ho implementato la mia piccola tecnica, che probabilmente ha un nome, ma passo semplicemente attraverso le mie 6 liste che sono ordinate in base agli assi su cui poggiano, seguite dal tipo di blocco e quindi dal livello di illuminazione. Ierate attraverso di essi, creando nuovi rettangoli mentre procedo e li coltivo simultaneamente (con una forte propensione verso un certo asse). Non è sicuramente ottimale, ma è piuttosto veloce e riduce il mio numero di vertici di circa il 50% in media. Il commento di Byte56 è l'armadio che penso a una vera risposta, ma non posso selezionarlo per la risposta / generosità.

Ecco il mio modo semplice e veloce che sto gestendo questo problema DOPO aver generato l'intero terreno iniziale senza molta ottimizzazione. Supponendo che tutti i quadrati indicati siano la stessa immagine, livello di luce, normale, ecc. Ogni colore è un quad diverso che renderei. Con i miei elenchi ordinati così come sono, questo è un approccio molto semplice / veloce.


Dopo tutte le ottimizzazioni, hai ancora problemi di prestazioni? Hai provato a profilare il codice per vedere dove sono i problemi?
MichaelHouse

@ Byte56 Oh, al momento non è affatto un problema di prestazioni. Potrebbe essere uno in futuro quando cerco di mettere ciò che sto imparando a usare per un gioco reale. Per ora però, voglio semplicemente imparare. Non ho dichiarato nulla di tutto ciò perché mi sembra di ricevere meno aiuto se voglio semplicemente imparare le cose semplicemente per impararle.
Mitici

Sento che dovrei anche dire che se riesco davvero a provare un gioco adeguato con questo, voglio che il mondo visibile sia ENORME. Non vorrei che il personaggio fosse alto 2 blocchi e largo 1 blocco come Minecraft e molti altri, ma più simile a 3 blocchi di larghezza / lunghezza e 6-9 di altezza. Probabilmente terreno statico però.
Mitici

1
Ah, ok Tim. Grazie per la spiegazione. Ho fatto qualche ricerca su questo mentre stavo costruendo il motore per il mio gioco. Dato che il mio panorama è dinamico, non pensavo che varrebbe il costo delle prestazioni ogni volta che qualcosa veniva cambiato. Tuttavia, potresti trovare un certo uso da questo articolo sul problema del rettangolo massimo. In sostanza è l'algoritmo di cui stai parlando per fondere volti simili (forse non avidi, ma ottimali). In bocca al lupo!
MichaelHouse

@ Byte56 Grazie, lo apprezzo molto. Questo sicuramente sembra più vicino al tipo di algoritmo che sto cercando, se non azzeccato. Dovrò armeggiare un po 'con esso per vedere se riesco a ottenere tutti i rettangoli massimi con una sola corsa. Potrei dare una ricompensa anche per questo in quanto penso che sia la domanda che una risposta dettagliata potrebbero aiutare molti altri in futuro.
Mitici

Risposte:


4

Vuoi solo fare strisce o, nel migliore dei casi, rettangoli. Non ci sono altre forme che saranno risolvibili o utili per te.

Vorrei anche sottolineare che mantenendo 6 elenchi per blocco, che in ogni momento userete 5 elenchi dai blocchi in direzioni cardinali e almeno 3 in ogni altro. Stai perdendo tempo qui, quando non solo la scheda video può fare questa ottimizzazione per te, ma anche se lo facessi da solo, sarebbe meglio tenere tutte le facce in un posto e confrontare il normale con la direzione con il camera (prodotto di ricerca DOT dei vettori).

I collegamenti di CaptainRedMuff sul meshing Greedy che hai già visto sono LA risposta al tuo problema. Dovrebbe anche essere chiaro da ciò che finirai con le maglie "Stripy", ma sono perfettamente efficaci, e venire con qualcosa di più ottimale sarà più complicato, e hai espresso che la maglia golosa è già troppo complicata.

Se hai problemi di prestazioni con un singolo pezzo, mi viene da pensare che qualcos'altro sia molto sbagliato.

La mia prima ipotesi sarebbe che stai chiamando un'operazione di sorteggio troppo spesso. Puoi solo dire alla scheda grafica di disegnare tra 50 e 400 ~ volte al secondo, a seconda dell'hardware. Quante chiamate stai effettuando a .setData o .draw ____ Primitive?


I rettangoli sono ciò che voglio. Byte56 ha collegato un algoritmo molto più semplice da seguire che avido, ma non posso accettare un commento come risposta. Supponevo invece che commentasse perché si collegava solo a un algoritmo anziché spiegarlo. Non so cosa intendi per quanto riguarda le mie liste. In genere ho 1-2 chiamate di disegno per blocco. Le mie liste sono memorizzate in un buffer per blocco. Cambio gli intervalli da disegnare per fotogramma. Potrei sbagliarmi, ma inviare dati non necessari alla GPU sembra controproducente. Un pareggio in più o due per blocco sembra meglio che inviare più dati alla gpu e costringerlo ad abbattere anche.
Mitici il

Non ho problemi di prestazioni. Mi piace semplicemente imparare queste cose. Modificherò la mia domanda per dire questo, ma come ho detto anche a Byte56, ottengo meno aiuto se quello che sto cercando di fare non sta effettivamente risolvendo un problema. Per rispondere alla tua domanda, attualmente eseguo il rendering di 200-260 blocchi al massimo per frame. Questo è un 500InsignitoPrimitives abbastanza comune per frame. Ricevo regolarmente 100-130 FPS senza vsync, facendo così 65.000 chiamate al secondo. Non sto cercando di essere scortese, ma poco che hai detto ha senso per me. Potrei non capire, quindi per favore elaborate se ho frainteso. Forse ha a che fare con XNA?
Mitici il

Ah, scusa, intendevo dire per fotogramma, non per secondo. Ti stai avvicinando a un limite superiore e, se sei solo su un terreno, sei quasi finito.
Phil

Ho fatto +1 sulla tua risposta perché mi ha fatto pensare ad alcuni miglioramenti che avrei potuto apportare, ma nulla a che fare con la domanda. Inoltre, ho pensato di condividere una risposta di Nathan Reed sull'eventuale collegamento al
Mythics,

Dovrò trovare l'articolo che ho letto che cita 400-500 come limite. Un veloce google non mi ha aiutato.
Phil

0

L'articolo a cui ti colleghi non fornisce in realtà un algoritmo per generare la mesh; indica un modo per valutare possibili soluzioni.

In generale, tuttavia, l'articolo fornisce un buon riassunto: 1) la soluzione ingenua è cattiva, 2) esiste una soluzione ottimale, ma sarà sia dispendioso in termini di tempo per scrivere che per eseguire, 3) una rapida selezione fornisce risultati molto migliori ( e questo è tutto ciò che Minecraft stesso fa), e infine 4) potrebbe esserci una soluzione più intelligente (l'algoritmo avido).

La "soluzione" che implica nell'immagine nella tua domanda è l'algoritmo avido. Sembra che la tua domanda sia "ho implementato correttamente la sua soluzione?" a cui devo rispondere "non ha dato una soluzione; l'hai risolto da solo."

La tua soluzione può essere migliore? Meh. Sicuro. Probabilmente non ne vale la pena. Penso che l'occlusione dell'abbattimento o LOD sarebbe meglio i prossimi passi. Minecraft spreca un buon numero di cicli disegnando la superficie anche quando sei sottoterra, oltre a disegnare vaste reti di sistemi di caverne e miniere quando sei in superficie. Una volta che hai una buona suddivisione della mesh, sì, sbarazzarsi di superfici oscurate può essere una buona cosa - ma (ad esempio) in genere è più veloce lasciare che la tua scheda video esegua l'abbattimento del backface piuttosto che farlo sulla CPU.

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.