Come determinare se una stanza basata su voxel 3D è sigillata, in modo efficiente


10

Ho riscontrato alcuni problemi nel determinare in modo efficiente se le stanze di grandi dimensioni sono sigillate in stanze 3D basate su voxel. Sono in un punto in cui ho fatto del mio meglio per risolvere il problema senza chiedere aiuto, ma non ho provato abbastanza a rinunciare, quindi chiedo aiuto.

Per chiarire, sigillato essendo che non ci sono buchi nella stanza. Ci sono sigillanti di ossigeno, che controllano se la stanza è sigillata e sigillano in base al livello di ingresso di ossigeno.

In questo momento, ecco come lo sto facendo:

  • A partire dal blocco sopra la piastrella del sigillante (lo sfiato si trova sulla faccia superiore del sigillante), ricicla in modo ricorsivo in tutte e 6 le direzioni adiacenti
  • Se la tessera adiacente è una tessera piena, non sotto vuoto, continuare attraverso il ciclo
  • Se la piastrella adiacente non è piena o è una piastrella a vuoto, verificare se i blocchi adiacenti lo sono, in modo ricorsivo.
  • Ogni volta che viene controllata una tessera, decrementa un contatore
  • Se il conteggio arriva a zero, se l'ultimo blocco è adiacente a una piastrella del vuoto, restituisce che l'area non è sigillata
  • Se il conteggio raggiunge lo zero e l'ultimo blocco non è una tessera sottovuoto, oppure il circuito ricorsivo termina (non rimangono tessere sottovuoto) prima che il contatore sia zero, l'area viene sigillata

Se l'area non è sigillata, eseguire nuovamente il ciclo con alcune modifiche:

  • Controllo dei blocchi adiacenti per la piastrella "aria respirabile" anziché una piastrella a vuoto
  • Invece di utilizzare un contatore decrementante, continua fino a quando non viene trovata alcuna piastrella ad "aria respirabile" adiacente.
  • Una volta terminato il ciclo, impostare ciascun blocco selezionato su una piastrella del vuoto.

Ecco il codice che sto usando: http://pastebin.com/NimyKncC

Il problema:

Sto eseguendo questo controllo ogni 3 secondi, a volte un sigillante dovrà passare attraverso centinaia di blocchi, e un grande mondo con molti sigillanti di ossigeno, questi cicli multipli ricorsivi ogni pochi secondi possono essere molto difficili per la CPU.

Mi chiedevo se qualcuno con più esperienza nell'ottimizzazione potesse darmi una mano, o almeno indirizzarmi nella giusta direzione. Grazie mille.


Controllare solo quando cambiano le cose sarebbe un inizio. Il controllo ogni tre secondi sembra eccessivo, poiché sai quando cambiano i voxel che potrebbero rompere il sigillo. Se un voxel che costituisce una stanza sigillata viene cambiato, puoi contrassegnare quella stanza da ricontrollare, altrimenti non preoccuparti.
MichaelHouse

Dato che potrebbero esserci centinaia di voxel cambiati in quel lasso di tempo di 3 secondi, ho pensato che sarebbe stato più efficiente farlo periodicamente piuttosto che verificare se qualcosa è cambiato nelle vicinanze. Lo sperimenterò comunque.
NigelMan1010,

Oh, beh, se centinaia di voxel possono cambiare in un intervallo di tempo di 3 secondi, probabilmente avrai un certo numero di problemi con le prestazioni. Inizia a profilare il tuo codice per trovare inefficienze. In bocca al lupo!
MichaelHouse

Risposte:


3

La soluzione migliore dipenderà da più fattori, come la dimensione prevista della stanza.

  1. Esegui solo questi controlli, quando qualcosa sta effettivamente cambiando.

Approccio 1:

È possibile utilizzare un A * per trovare un percorso dallo sfiato alla piastrella sopra lo sfiato / lo sfiato stesso o verso una piastrella nota come vaccum. Se viene trovato il percorso, la stanza non viene sigillata. Questo non è così diverso dal tuo attuale approccio ma dovrebbe essere più veloce. Una volta trovato, effettuare un "riempimento di inondazione" per impostare le piastrelle come vuoto.

Approccio 2:

Forse la tua struttura esterna è meno complessa - considerando che esiste una superficie in cui ci sono le stanze, non è necessario spostarsi in tutte e 6 le direzioni, quindi dovresti viaggiare lungo la superficie, contrassegnare ogni piastrella come vuoto che viaggi.


0

Quando esegui una ricerca ricorsiva, ti assicuri di non controllare più volte lo stesso voxel? Non saprei dire dal modo in cui hai descritto il tuo algoritmo, ma dovresti avere una sorta di flag per indicare se hai già espanso ricorsivamente un voxel, quindi non lo fai più di una volta.

E come ha detto Byte56, dovresti anche controllare le perdite solo quando le cose cambiano. Ciò potrebbe ridurre al minimo la quantità di lavoro svolto, a seconda della frequenza con cui si verificano i cambiamenti. Potresti anche essere in grado di memorizzare nella cache informazioni tra chiamate successive all'algoritmo, il che può banalizzare la quantità di calcolo che fai dopo la prima chiamata.

Modificare:

Ho guardato un po 'del tuo codice. Sembra che tu stia usando una LinkedList per indicare se un voxel è già stato controllato, come nel mio primo paragrafo. Potresti ottenere risultati migliori se usi qualcosa di diverso da una LinkedList per questo. Forse provare un HashSet o qualcosa del genere? Ciò dovrebbe ridurre la complessità del metodo di controllo da O (n) a O (1).


Sì, lo sto aggiungendo a un LinkedList chiamato "controllato", quindi controllo se tale elenco contiene la posizione prima di controllarlo. Ho pensato che verificare se qualcosa fosse cambiato avrebbe richiesto anche un uso intensivo della CPU, dal momento che centinaia di voxel avrebbero potuto cambiare in quel periodo di 3 secondi. Vedrò come un hashset si confronta con la linklist in questa situazione, grazie.
NigelMan1010,
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.