Costruire un Octree per la generazione del terreno


9

In precedenza ho implementato cubi / tetraedri per rendere un IsoSurface. Ha funzionato ( YouTube ), ma la performance è stata terribile in quanto non ho mai avuto l'implementazione del livello di dettaglio variabile in base alla distanza di visualizzazione (o addirittura alla rimozione di blocchi vecchi e distanti).

Ho deciso di provare un'altra volta e farlo correttamente questa volta. Ho iniziato creando un OctreeNode che funziona come segue quando Build()viene chiamato.

  • Se il pezzo è troppo piccolo per essere costruito, ritorna immediatamente.
  • Risolvi se la superficie passa attraverso il volume di questo pezzo.
  • In tal caso, quindi decidere se vogliamo aumentare il LOD (perché la fotocamera è vicina)
  • In tal caso, genera 8 bambini e chiama lo stesso processo su di essi
  • In caso contrario, creare la mesh utilizzando le dimensioni del nodo corrente

Alcuni PseudoCode:

OctNode Build() {
    if(this.ChunkSize < minChunkSize) {
        return null;
    }
    densityRange = densitySource¹.GetDensityRange(this.bounds);
    if(densityRange.min < surface < densityRange.max) {
        if(loDProvider.DesiredLod(bounds > currentLoD) {
            for(i 1 to 8) {
                if(children[i] == null) {
                    children[i] = new OctNode(...)
                }
                children[i] = children[i].Build();
            }
        } else {
            BuildMesh();
        }
        return this;
    }
}

¹ Oltre a restituire la densità in un punto, la sorgente di densità può determinare la possibile gamma di densità per un dato volume.

² Il provider LoD prende un riquadro di selezione e restituisce il LoD massimo desiderato in base alla posizione / frustum della telecamera, alle impostazioni dell'utente, ecc ...

Quindi ... Tutto funziona abbastanza bene. Utilizzando una sfera semplice come sorgente Densità e mostrando tutti i nodi:

Ottobre completo

E solo le foglie:

Octree che mostra solo foglie

Tuttavia, ci sono un paio di problemi:

  • Devo definire il volume iniziale di delimitazione (e più è grande, più elaborazione devo fare)
  • Alla radice dell'albero, non ho idea di quanto saranno profonde le foglie, quindi la mia numerazione LoD inizia con la qualità più bassa (radice) e aumenta man mano che i blocchi diventano più piccoli. Poiché LoD è ora relativo al volume iniziale, non è molto utile quando voglio fare cose con dimensioni / qualità specifiche.

Ho pensato a un paio di opzioni ma entrambi sembrano imperfetti:

  • Mantieni una raccolta di Octrees e aggiungi / rimuovi in ​​base alla distanza. Non riesco a vedere come fare a maglie bene¹, inoltre avrei bisogno di un elenco di nodi vuoti noti, soprattutto se desidero superfici 3D arbitrarie (per evitare di ricalcolare ripetutamente i volumi vuoti)
  • Aggiungi un nodo padre alla radice corrente, quindi aggiungi sette fratelli per il nodo originale. Funzionerebbe e sarebbe on demand, ma sembra complesso ridursi sensibilmente mentre il giocatore si muove attraverso il paesaggio. Renderebbe anche i numeri LoD ancora meno significativi.

¹ [In chiarimento a Q sotto] Al momento, se 2 nodi fisicamente adiacenti nella struttura sono in LOD diversi, ho un po 'di codice per forzare i verbi in modo tale che non ci siano cuciture quando vengono generate le mesh. Sono in grado di farlo conoscendo la densità per più nodi circostanti. In uno scenario in cui ho 2 ocre indipendenti fianco a fianco, non avrei un modo semplice per recuperare queste informazioni, risultando in cuciture.

Qual è un modo ottimale per affrontare questo?

Risposte:


1

Non sono sicuro di rispondere alla domanda esatta, quindi vado a rispondere in segmenti e mi sento libero di rispondere nei commenti se c'è un malinteso sui dettagli di una domanda specifica.

Devo definire il volume iniziale di delimitazione (e più è grande, più elaborazione devo fare)

Questo non sembra che dovrebbe essere il caso. Dal momento che l'ottava aumenta in modo esponenziale la granularità, l'aggiunta di alcuni livelli nella parte superiore dovrebbe comportare un aumento netto molto ridotto del risultato prestazionale.

Alla radice dell'albero, non ho idea di quanto saranno profonde le foglie, quindi la mia numerazione LoD inizia con la qualità più bassa (radice) e aumenta man mano che i blocchi diventano più piccoli. Poiché LoD è ora relativo al volume iniziale, non è molto utile quando voglio fare cose con dimensioni / qualità specifiche.

Se fissi il tuo octree radice su un "valore abbastanza grande", allora "LoD relativo al volume iniziale" non dovrebbe essere un problema. E come accennato in precedenza, non credo che avere un livello extra nella parte superiore influirà sulle prestazioni complessive.

Mantieni una raccolta di Octrees e aggiungi / rimuovi in ​​base alla distanza. Non riesco a vedere come fare a maglie bene, inoltre avrei bisogno di un elenco di nodi vuoti noti, soprattutto se desidero superfici 3D arbitrarie (per evitare di ricalcolare ripetutamente i volumi vuoti)

A quanto ho capito, questa soluzione proposta riguarda l'abbassamento del LoD quando ci si allontana da un'area precedentemente dettagliata. Immagino che dovrebbe apparire molto simile al percorso del codice "crescente LoD":

if (loDProvider.DesiredLod(bounds) <(is a lot less than)< currentLoD) { 
    for(i = 1 to 8) { 
        children[i].Destroy();
    }
    BuildMesh();
}

Quindi, non stai trascorrendo troppo tempo a controllare nodi distanti perché puoi fare affidamento sul fatto che, sebbene lontani, non ci sono troppi nodi "attivi", poiché tutti i nodi ad alta risoluzione saranno stati rimossi.


Supponendo che i piccoli nodi siano su scala rock, ciò significherebbe potenzialmente dozzine se non centinaia di livelli mentre viaggio attraverso un continente

Penso che la scala logaritmica dell'ottico lo renda ancora possibile. Se il tuo livello superiore è largo 1.000,0000.000 m (questo sarebbe 25 volte più largo della Terra reale e con 625x l'area della superficie) e i tuoi bit di livello più basso hanno una larghezza di 10 cm, ovvero 32 livelli nell'ottavo, che è probabilmente abbastanza gestibile. Se volevi un pianeta 100 volte più largo della Terra (e con 10000 volte più superficie), questo è solo un ulteriore 3-4 livelli nel tuo octree. A questo punto un giocatore impiegherebbe centinaia di anni a camminare per il mondo, e se usi la matematica ingenua in virgola mobile il mondo accumulerà errori di precisione.

Mantieni una raccolta di Octrees e aggiungi / rimuovi in ​​base alla distanza. Non riesco a vedere come fare a maglie bene¹, inoltre avrei bisogno di un elenco di nodi vuoti noti, soprattutto se desidero superfici 3D arbitrarie (per evitare di ricalcolare ripetutamente i volumi vuoti)

Questo non è fondamentalmente equivalente ad avere l'ottetto di miliardi di km ma mantenere un elenco di puntatori per ogni, diciamo, blocco di 1 km? Quindi il "meshing through" si baserebbe semplicemente sui nodi di dimensioni di 2 km. Mantenere un riferimento locale a ciascun "blocco di grandi dimensioni" di medio livello ti impedisce anche di dover scorrere i nodi di livello superiore, se sei preoccupato per le "possibilmente dozzine di livelli aggiuntivi di otto"


Grazie per aver risposto. Non posso semplicemente scegliere un volume iniziale enorme poiché il mio terreno è infinito (questo è il mio obiettivo). Guarda il video per avere un'idea. Come tale, il mio albero dei nodi sarebbe diventato sempre più alto. Supponendo che i piccoli nodi siano su scala rock, ciò significherebbe potenzialmente dozzine se non centinaia di livelli mentre viaggio attraverso un continente. Ri: Meshing through, fammi aggiungere qualche dettaglio in più alla domanda [Fatto]
Basic

per quanto riguarda il giocatore, "un miliardo di miglia" è abbastanza vicino a "infinito". Altri argomenti per un volume iniziale fisso aggiunto alla risposta.
Jimmy

Non sono ancora convinto. Perché avere più di 30 livelli di elaborazione noti inutili? Non è elegante, figuriamoci efficiente. Prendo il tuo punto sul tempo per attraversare, ma stiamo semplicemente parlando della generazione del terreno. Nulla di ciò che dice che devo centrare l'origine, né che volare ad alta velocità è impossibile (anche se non mi sarei mosso a quella velocità!). FWIW Sto usando i doppi internamente per evitare quel problema di precisione.
Base
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.