Ho un background di ingegneria civile ed eseguo regolarmente analisi idrauliche e idrologiche. Vendono lauree per quel genere di cose, ma in realtà non è scienza missilistica. Recentemente mi è venuto in mente di implementare l'intero processo idrologico e idraulico per un terreno sulla GPU. Ho appreso shader di calcolo solo di recente, quindi attualmente sono bloccato a essere più bravo in ingegneria che a progettare flussi di lavoro GPU paralleli.
Puoi calcolare la quantità di acqua generata durante un evento di pioggia usando la formula:
Q (CF/S) = c * I (in/hr) * A (acres)
Ho difficoltà ad andare oltre il calcolo della "superficie" anche della prima area.
Panoramica attuale dell'attuazione:
- Il terreno è una griglia regolare di vertici a intervalli di 1 unità
- Una heightmap contiene un valore di altezza R32 per ciascun vertice
- Attualmente, consento il flusso solo nelle 4 direzioni cardinali (senza diagonali)
- Sto usando un Texture2D [int] come uno stencil per i vertici che ho già analizzato
Algoritmo corrente:
- Quando lo strumento terreno è stato attivo e ora non lo è ....
- Cancella lo "stencil".
- Scansiona l'intero terreno per la quota più bassa.
- Quel singolo punto è l'input iniziale per CS_Flood.
- CS_Flood effettua un passaggio sull'asse X.
- Ogni vertice di input viene proiettato nelle direzioni X e X + fino a 2048 volte.
- Trovare un vertice adiacente con una coordinata OOB indica il bordo del terreno in questa direzione. CurrentPoint viene aggiunto al buffer BoundaryPoints e il ciclo di proiezione per quella direzione viene terminato. È stato facile e funziona sempre bene.
- Vertici adiacenti con altezze> = l'altezza del vertice corrente sono contrassegnati nello stencil e aggiunti al buffer NextPass.
- Vertici adiacenti con altezze <l'altezza del vertice corrente indica il picco di una cresta e termina il circuito di proiezione. Una futura iterazione del riempimento di inondazione potrebbe scorrere intorno alla base della cresta, lungo il lato "posteriore" di esso e rilevare la stessa cresta una seconda volta.
- Qualsiasi punto di picco / cresta che viene rilevato più di una volta non sarà un BoundaryPoint, a questo scopo.
- Qualsiasi punto di picco / cresta rilevato esattamente una volta viene aggiunto a BoundaryPoints e il circuito di proiezione in quella direzione viene terminato.
- CS_Flood esegue un passaggio dell'asse Z con lo stesso codice, utilizzando come input i punti generati dal passaggio dell'asse X.
- Al momento, CS_Flood continua a alternare indefinitamente tra le due direzioni. Alla fine, terminerò il ciclo generale ogni volta che CS_Flood viene completato e il buffer NextPass è vuoto.
Idealmente, a quel punto, BoundaryPoints conterrebbe ogni vertice che si verifica sulla divisione del drenaggio naturale. Le gocce d'acqua che atterrano all'interno del confine alla fine scorrono nello stesso punto basso. Le gocce d'acqua che atterrano al di fuori del confine vanno "altrove".
Poi:
- Senza cancellare lo stencil, ripetere la scansione del terreno per il vertice più basso, non stencil.
- Iterate CS_Flood.
- Ripeti fino a quando lo stencil è pieno (o qualcosa di simile).
Il 3D è difficile da percepire con questi colori; questo mostra le curve di livello alle quote integrali:
(un buco circondato da un berme vicino al bordo)
Esistono circa 10 modi unici per drenare attraverso un vertice; dando a ciascuno un colore unico si presenta come:
(segni circolari visibili, "creste" si presentano bene)
Questo mostra ogni punto generato da CS_Flood, confine o altro, come POINTLIST:
L'algoritmo funziona quasi sempre . A volte funziona anche correttamente. Altre volte, l'algoritmo è chiaramente contenuto nella forma corretta ma continuerà a generare punti indefinitamente. Come visto nel terzo screenshot, a volte viene confuso. Ci deve essere un'altra situazione / fattore che ho trascurato. Gradirei qualsiasi aiuto per trovare la mia supervisione o suggerimenti su modi più semplici e / o più eleganti per attaccare il problema.
MissingPoint! può essere incluso aiutando la banda dell'algoritmo per aggiungere ogni nuovo BoundaryPoint rilevato al buffer NextPass. Durante il passaggio successivo, il 99% dei punti generati da tale cerotto perderà una piccola quantità di tempo GPU determinando che non possono andare da nessuna parte e non fare nulla. Durante il primo passaggio, l'invio di LowestPoint insieme agli altri punti NextPass gestirà anche questo scenario specifico.
So che è plausibile e, dato il tempo sufficiente, sarò in grado di aiutarlo abbastanza da fare quello che voglio. Mi piacerebbe farlo in un modo migliore, più intelligente, più veloce, se possibile, e non ho ancora abbastanza esperienza per conoscerlo meglio.