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
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);
}
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
Questo è vero, anche se è da qualche parte nell'algoritmo e non ho idea di dove. Non è troppo codice, quindi lo posterò anche qui. –