2014-07-02 9 views
7

Ho cercato di implementare le equazioni di acque basse in Unity, ma ho avuto un bug strano. Prendo queste strane increspature oscillanti nella mia acqua. Ho fatto un po 'di screenshot:Increspature strane oscillanti nella mia implementazione in acque poco profonde

enter image description hereenter image description here

E un video che potete trovare qui: https://www.youtube.com/watch?v=crXLrvETdjA

ho basato il mio codice sulla carta Fast Hydraulic Erosion Simulation and Visualization on GPU da Xing Mei. E puoi trovare l'intero codice del risolutore qui: http://pastebin.com/JktpizHW (o vedi sotto). Ogni volta che uso una formula dalla carta, ho aggiunto il suo numero come commento.

Ho provato diversi timestep, per il video ho usato 0.02, abbassandolo lo ho fatto oscillare più lentamente. Ho anche provato una griglia più grande (il video usa 100, ho provato 200 ma le increspature erano più piccole). Ho controllato tutte le formule più volte e non ho trovato alcun errore.

Chiunque qui può capire cosa non va?

Info extra:

Come si può vedere dalla pastebin, ho programmato in C#. Ho usato Unity come motore per la visualizzazione e sto solo usando una griglia per visualizzare l'acqua. Modifico il componente vertice y della mesh in modo che corrisponda all'altezza calcolata.

Il metodo DoUpdate ha un parametro float[][] lowerLayersHeight, che è in pratica l'altezza del terreno sott'acqua. Nel video è solo tutto 0.

public override void DoUpdate(float dt, float dx, float[][] lowerLayersHeight) { 
     int x, y; 
     float totalHeight, dhL, dhR, dhT, dhB; 
     float dt_A_g_l = dt * _A * g/dx; //all constants for equation 2 
     float K; // scaling factor for the outflow flux 
     float dV; 

     for (x=1 ; x <= N ; x++) { 
       for (y=1 ; y <= N ; y++) { 
         // 
         // 3.2.1 Outflow Flux Computation 
         // -------------------------------------------------------------- 
         totalHeight = lowerLayersHeight[x][y] + _height[x][y]; 
         dhL = totalHeight - lowerLayersHeight[x-1][y] - _height[x-1][y]; //(3) 
         dhR = totalHeight - lowerLayersHeight[x+1][y] - _height[x+1][y]; 
         dhT = totalHeight - lowerLayersHeight[x][y+1] - _height[x][y+1]; 
         dhB = totalHeight - lowerLayersHeight[x][y-1] - _height[x][y-1]; 

         _tempFlux[x][y].left = Mathf.Max(0.0f, _flux[x][y].left  + dt_A_g_l * dhL); //(2) 
         _tempFlux[x][y].right = Mathf.Max(0.0f, _flux[x][y].right  + dt_A_g_l * dhR); 
         _tempFlux[x][y].top = Mathf.Max(0.0f, _flux[x][y].top   + dt_A_g_l * dhT); 
         _tempFlux[x][y].bottom = Mathf.Max(0.0f, _flux[x][y].bottom  + dt_A_g_l * dhB); 

         float totalFlux = _tempFlux[x][y].left + _tempFlux[x][y].right + _tempFlux[x][y].top + _tempFlux[x][y].bottom; 
         if (totalFlux > 0) { 
           K = Mathf.Min(1.0f, _height[x][y] * dx * dx/totalFlux/dt); //(4) 

           _tempFlux[x][y].left = K * _tempFlux[x][y].left; //(5) 
           _tempFlux[x][y].right = K * _tempFlux[x][y].right; 
           _tempFlux[x][y].top = K * _tempFlux[x][y].top; 
           _tempFlux[x][y].bottom = K * _tempFlux[x][y].bottom; 
         } 
         //swap temp and the real one after the for-loops 

         // 
         // 3.2.2 Water Surface 
         // ---------------------------------------------------------------------------------------- 
         dV = dt * (
           //sum in 
           _tempFlux[x-1][y].right + _tempFlux[x][y-1].top + _tempFlux[x+1][y].left + _tempFlux[x][y+1].bottom 
           //minus sum out 
           - _tempFlux[x][y].right - _tempFlux[x][y].top - _tempFlux[x][y].left - _tempFlux[x][y].bottom 
           ); //(6) 
         _tempHeight[x][y] = _height[x][y] + dV/(dx*dx); //(7) 
         //swap temp and the real one after the for-loops 
       } 
     } 
     Helpers.Swap(ref _tempFlux, ref _flux); 
     Helpers.Swap(ref _tempHeight, ref _height); 
} 
+0

Stackoverflow consiglia di pubblicare il frammento di codice più piccolo che riproduce il problema o è la parte più pertinente del problema direttamente nel testo della risposta. Questo è così che la domanda può rimanere rilevante per i googler in futuro; se si collega a pastebin, il pastebin può essere eliminato e questa domanda diventa inutile per gli utenti futuri perché non possono vedere il codice. – antiduh

+0

Questo è vero, anche se è da qualche parte nell'algoritmo e non ho idea di dove. Non è troppo codice, quindi lo posterò anche qui. –

risposta

6

L'ho riparato da solo! Anche se durante la guida ad un amico. Il problema è abbastanza semplice, quello che faccio nel codice bugged è per ogni cella (o punto-griglia) che calcola il flusso, poi l'altezza e poi vado alla cella successiva. Quello che dovrei fare è prima calcolare il flusso per tutte le celle, quindi scorrere una seconda volta su tutte le celle e calcolare la loro altezza. Così il codice diventa:

for (x=1 ; x <= N ; x++) { 
    for (y=1 ; y <= N ; y++) { 
     // 
     // 3.2.1 Outflow Flux Computation 
     // -------------------------------------------------------------- 
     *** 
    } 
} 

for (x=1 ; x <= N ; x++) { 
    for (y=1 ; y <= N ; y++) { 
     // 
     // 3.2.2 Water Surface 
     // --------------------------------------------------------------------------- 
     *** 
    } 
} 
Helpers.Swap(ref _tempFlux, ref _flux); 
Helpers.Swap(ref _tempHeight, ref _height); 

(Naturalmente *** diventa il codice corrispondente dalla domanda di cui sopra.)

Ora ho una simulazione di acqua di lavoro.

+0

Questo è un errore molto comune da fare dovrebbe avere il suo nome :) È un classico del Conway's Game of Life, ad esempio, e l'ho visto alcune volte in varie simulazioni numeriche. –

+0

Ciao, puoi dare maggiori dettagli su come eseguire questo, devo fare un progetto simile e io sono un ragazzo di C#, mi piacerebbe farlo in C# invece di C++ – Musaab

+0

Il codice è C#. È scritto in Unity. –