Metodo efficiente di rendering di terreni di massa in XNA


10

Sto creando un gioco XNA che richiede uno spazio enorme per i giocatori. Attualmente, la mappa di altezza del test che sto usando è 4096x4096 e viene salvata come BMP a 4 bit.

Quello che sto cercando di fare è prendere quell'enorme file heightmap e renderlo nel gioco. Il problema che sto incontrando è il fatto che è inefficiente caricare l'intero terreno in memoria contemporaneamente, poiché utilizzerà la maggior parte della memoria disponibile.

Un altro problema che ho riscontrato è che non riesco a rendere il terreno tutto in una primitiva a causa di un limite rigido impostato in XNA.

Detto questo, ho trovato una serie di soluzioni, tutte elencate di seguito:

  • Rendering basato sulla posizione dell'utente corrente - fondamentalmente disegnando un quadrato intorno all'utente indipendentemente dal loro orientamento all'interno del mondo. Non è esattamente quello che volevo, perché stai ancora rendendo lo spazio che l'utente non vede.
  • Rendering basato sull'orientamento e sulla posizione dell'utente - Ho trovato una formula per recuperare un triangolo che dovrebbe avere i pixel della mappa di altezza che dovrebbero essere rappresentati, ma questo si è rivelato molto difficile.
  • Dividere il terreno in più blocchi e renderizzare quelli più vicini all'utente - Ancora non molto efficiente poiché stai ancora eseguendo il rendering di blocchi che le persone non vedranno. Ed è un lavoro intenso perché poi devo dividere la mia altezza in diversi pezzi e la scalabilità diventa un grosso problema.

Dopo aver provato quelle soluzioni, sono appena uscito dalle idee su cosa fare. Ho ricevuto alcune risposte in cui le persone mi stanno dicendo di fare questi algoritmi complessi, ma semplicemente non ho idea di come approcciarli.

Quindi, in sostanza, sto chiedendo un modo semplice e diretto per rendere terreni giganteschi in XNA con la massima efficienza.

Sono piuttosto nuovo nello sviluppo di giochi in generale, ma sono disposto a ricercare se sembra promettente.

Aggiornamento 1: dopo aver ricercato il metodo di geoclipmapping, ho iniziato a programmare con quello. Ho fatto tutta la matematica e il gioco funziona. Tuttavia, è estremamente inefficiente, il che probabilmente è una cattiva codifica da parte mia. Funziona a 2FPS e utilizza un intero nucleo della mia CPU. Proverò a migliorare il codice, ma penso che avrò bisogno di più aiuto, quindi ecco un esempio del codice per la classe del gestore del terreno. Riporterò più risultati in seguito, se mai riuscissi a renderlo più efficiente.


1
È interessante notare che la tecnica di cui stai parlando sembra simile a quella che ID Software sta usando nel loro prossimo gioco, Rage. Usano una "megatexture" e quindi trasmettono in streaming le parti necessarie nella GPU. Ne ha parlato, ma ecco un articolo di Wikipedia, potrebbe essere d'ispirazione: en.wikipedia.org/wiki/MegaTexture

Risposte:


5

L'approccio a blocchi è in genere ciò che viene utilizzato. Raramente è efficace testare ogni triangolo su centinaia di migliaia per vedere se dovresti renderlo. Invece la maggior parte degli algoritmi di rendering del terreno impiegano una struttura di dati spaziali per eseguire il rendering dinamico delle parti visibili del terreno.

Una struttura di dati facile da implementare si chiama quadtree . In breve, per usare un quadrifoglio troverai il frustum di visualizzazione del giocatore, lo intersechi contro il livello superiore del quadrifoglio e per tutti i pezzi che sono parzialmente visualizzabili (cioè, i piani del frustum intersecano il blocco) suddividi e testa tutti i bambini pezzi, omettendo quelli fuori dal frustum. Ciò fornirà un'approssimazione abbastanza vicina alla geometria visibile effettiva con solo pochi livelli di ricorsione.

I renderer di terreno più avanzati utilizzano un algoritmo per ottimizzare non solo la geometria visualizzabile ma anche i dettagli di quella geometria. Il geomipmapping (e il relativo geoclipmapping) è relativamente popolare al momento per farlo, ma non è una cosa banale da implementare.

modifica: ecco una descrizione decente sia del geoclipmapping che dell'abbattimento del frustum.

Ho anche qualche dubbio sul fatto che 4 bit per la heightmap siano effettivamente sufficienti per produrre un terreno dall'aspetto gradevole a meno che tu non stia facendo un sacco di livellamento sul risultato.


Ho dato un'occhiata a quell'articolo e ho deciso che avrò prima il metodo di geoclipmapping, in quanto sembra che sarebbe il più efficiente per visualizzare una grande quantità di terreno. Riporterò indietro con i miei risultati.

3

Qualsiasi approccio che richiede di eseguire il lavoro per frame per caricare i dati sulla GPU sarà difettoso.

Ecco uno schema generale di un approccio che dovrebbe funzionare bene:

Dovresti dividere il tuo terreno in blocchi (abbastanza grandi), caricando quei blocchi in buffer di vertici fissi (la profondità di bit della tua mappa di altezza non ha importanza!). Quei buffer di vertici rimarranno semplicemente nella memoria della GPU, in attesa di essere renderizzati. Dovrai sperimentare una dimensione del pezzo appropriata, ma 128x128 è forse un buon punto di partenza.

Per un terreno 4096x4096 sei un po 'oltre il limite di quello che mi piacerebbe caricare sulla GPU in una volta - probabilmente sono poche centinaia di MB di dati vertici (anche se potresti farlo fino a ~ 64 MB se sei intelligente). Quindi potrebbe essere necessario caricare e scaricare i buffer dei vertici dalla GPU in background.

(Se si implementa il caricamento in background di blocchi, questo dovrebbe essere estremamente scalabile!)

Dopo aver ottenuto i dati del vertice sulla GPU, è il momento opportuno per eseguire la selezione della visibilità su una base per blocco . Non è necessario inviare il comando per eseguire il rendering di un blocco, se sai che è dietro la telecamera.

Non dovresti quasi mai fare l' abbattimento per triangolo sulla CPU!

La GPU eliminerà i triangoli fuori dallo schermo molto più velocemente di quanto tu possa mai fare.

Per ulteriori informazioni sulle prestazioni, dai un'occhiata a questa risposta sul sito Game Dev.


0

Non sono un esperto di XNA in alcun modo, quindi per favore correggimi se sbaglio, ma avevo l'impressione che in realtà ci sia ottimizzazione integrata per situazioni come questa. So che sei in grado di impostare una distanza di rendering e dopo quel punto non esegue il rendering di nulla, nel tuo caso sarebbe il terreno rimanente. Tuttavia, questo lascia un vantaggio alquanto poco attraente per il tuo mondo reso, quindi dovresti implementare qualcosa come l'appannamento che la maggior parte dei giochi open world ha.


Esistono soluzioni integrate, ma il problema che ho riscontrato è stato il tentativo di rendere una grande primitiva, che ha superato il limite di poligoni per le primitive. Pertanto, non attirerebbe, basta lanciare un'eccezione.
sammarks,
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.