188 lines
5.3 KiB
C#
188 lines
5.3 KiB
C#
using OpenTK.Mathematics;
|
|
|
|
namespace fluidsC_;
|
|
|
|
public class FluidSimulation
|
|
{
|
|
private readonly int _sizeX;
|
|
private readonly int _sizeY;
|
|
|
|
// Fluid fields
|
|
private float[,] _density;
|
|
private float[,] _densityOld;
|
|
|
|
// Velocity fields
|
|
private float[,] _vx;
|
|
private float[,] _vy;
|
|
private float[,] _vxOld;
|
|
private float[,] _vyOld;
|
|
|
|
public FluidSimulation(int sizeX, int sizeY)
|
|
{
|
|
_sizeX = sizeX;
|
|
_sizeY = sizeY;
|
|
|
|
// Initialize arrays in constructor to fix nullable warnings
|
|
_density = new float[_sizeX, _sizeY];
|
|
_densityOld = new float[_sizeX, _sizeY];
|
|
_vx = new float[_sizeX, _sizeY];
|
|
_vy = new float[_sizeX, _sizeY];
|
|
_vxOld = new float[_sizeX, _sizeY];
|
|
_vyOld = new float[_sizeX, _sizeY];
|
|
}
|
|
|
|
public void AddDensity(int x, int y, float amount)
|
|
{
|
|
if (x >= 0 && x < _sizeX && y >= 0 && y < _sizeY)
|
|
{
|
|
_density[x, y] += amount;
|
|
}
|
|
}
|
|
|
|
public void AddVelocity(int x, int y, float amountX, float amountY)
|
|
{
|
|
if (x >= 0 && x < _sizeX && y >= 0 && y < _sizeY)
|
|
{
|
|
_vx[x, y] += amountX;
|
|
_vy[x, y] += amountY;
|
|
}
|
|
}
|
|
|
|
public void Step(float dt, float diffusion, float viscosity)
|
|
{
|
|
Diffuse(1, _vxOld, _vx, viscosity, dt);
|
|
Diffuse(2, _vyOld, _vy, viscosity, dt);
|
|
|
|
Project(_vxOld, _vyOld, _vx, _vy);
|
|
|
|
Advect(1, _vx, _vxOld, _vxOld, _vyOld, dt);
|
|
Advect(2, _vy, _vyOld, _vxOld, _vyOld, dt);
|
|
|
|
Project(_vx, _vy, _vxOld, _vyOld);
|
|
|
|
Diffuse(0, _densityOld, _density, diffusion, dt);
|
|
Advect(0, _density, _densityOld, _vx, _vy, dt);
|
|
}
|
|
|
|
private void Diffuse(int b, float[,] x, float[,] x0, float diff, float dt)
|
|
{
|
|
float a = dt * diff * (_sizeX - 2) * (_sizeY - 2);
|
|
LinearSolve(b, x, x0, a, 1 + 4 * a);
|
|
}
|
|
|
|
private void LinearSolve(int b, float[,] x, float[,] x0, float a, float c)
|
|
{
|
|
for (int k = 0; k < 20; k++)
|
|
{
|
|
for (int i = 1; i < _sizeX - 1; i++)
|
|
{
|
|
for (int j = 1; j < _sizeY - 1; j++)
|
|
{
|
|
x[i, j] = (x0[i, j] + a * (x[i - 1, j] + x[i + 1, j] + x[i, j - 1] + x[i, j + 1])) / c;
|
|
}
|
|
}
|
|
SetBoundary(b, x);
|
|
}
|
|
}
|
|
|
|
private void Project(float[,] velocX, float[,] velocY, float[,] p, float[,] div)
|
|
{
|
|
for (int i = 1; i < _sizeX - 1; i++)
|
|
{
|
|
for (int j = 1; j < _sizeY - 1; j++)
|
|
{
|
|
div[i, j] = -0.5f * (
|
|
velocX[i + 1, j] - velocX[i - 1, j] +
|
|
velocY[i, j + 1] - velocY[i, j - 1]
|
|
) / _sizeX;
|
|
p[i, j] = 0;
|
|
}
|
|
}
|
|
|
|
SetBoundary(0, div);
|
|
SetBoundary(0, p);
|
|
LinearSolve(0, p, div, 1, 4);
|
|
|
|
for (int i = 1; i < _sizeX - 1; i++)
|
|
{
|
|
for (int j = 1; j < _sizeY - 1; j++)
|
|
{
|
|
velocX[i, j] -= 0.5f * (p[i + 1, j] - p[i - 1, j]) * _sizeX;
|
|
velocY[i, j] -= 0.5f * (p[i, j + 1] - p[i, j - 1]) * _sizeY;
|
|
}
|
|
}
|
|
|
|
SetBoundary(1, velocX);
|
|
SetBoundary(2, velocY);
|
|
}
|
|
|
|
private void Advect(int b, float[,] d, float[,] d0, float[,] velocX, float[,] velocY, float dt)
|
|
{
|
|
float dt0 = dt * (_sizeX - 2);
|
|
|
|
for (int i = 1; i < _sizeX - 1; i++)
|
|
{
|
|
for (int j = 1; j < _sizeY - 1; j++)
|
|
{
|
|
float x = i - dt0 * velocX[i, j];
|
|
float y = j - dt0 * velocY[i, j];
|
|
|
|
x = Math.Clamp(x, 0.5f, _sizeX - 1.5f);
|
|
y = Math.Clamp(y, 0.5f, _sizeY - 1.5f);
|
|
|
|
int i0 = (int)Math.Floor(x);
|
|
int i1 = i0 + 1;
|
|
int j0 = (int)Math.Floor(y);
|
|
int j1 = j0 + 1;
|
|
|
|
float s1 = x - i0;
|
|
float s0 = 1 - s1;
|
|
float t1 = y - j0;
|
|
float t0 = 1 - t1;
|
|
|
|
d[i, j] = s0 * (t0 * d0[i0, j0] + t1 * d0[i0, j1]) +
|
|
s1 * (t0 * d0[i1, j0] + t1 * d0[i1, j1]);
|
|
}
|
|
}
|
|
|
|
SetBoundary(b, d);
|
|
}
|
|
|
|
private void SetBoundary(int b, float[,] x)
|
|
{
|
|
for (int i = 1; i < _sizeX - 1; i++)
|
|
{
|
|
x[i, 0] = b == 2 ? -x[i, 1] : x[i, 1];
|
|
x[i, _sizeY - 1] = b == 2 ? -x[i, _sizeY - 2] : x[i, _sizeY - 2];
|
|
}
|
|
|
|
for (int j = 1; j < _sizeY - 1; j++)
|
|
{
|
|
x[0, j] = b == 1 ? -x[1, j] : x[1, j];
|
|
x[_sizeX - 1, j] = b == 1 ? -x[_sizeX - 2, j] : x[_sizeX - 2, j];
|
|
}
|
|
|
|
x[0, 0] = 0.5f * (x[1, 0] + x[0, 1]);
|
|
x[0, _sizeY - 1] = 0.5f * (x[1, _sizeY - 1] + x[0, _sizeY - 2]);
|
|
x[_sizeX - 1, 0] = 0.5f * (x[_sizeX - 2, 0] + x[_sizeX - 1, 1]);
|
|
x[_sizeX - 1, _sizeY - 1] = 0.5f * (x[_sizeX - 2, _sizeY - 1] + x[_sizeX - 1, _sizeY - 2]);
|
|
}
|
|
|
|
public float GetDensity(int x, int y)
|
|
{
|
|
if (x >= 0 && x < _sizeX && y >= 0 && y < _sizeY)
|
|
return _density[x, y];
|
|
return 0;
|
|
}
|
|
|
|
public void FadeDensity(float amount)
|
|
{
|
|
for (int i = 0; i < _sizeX; i++)
|
|
{
|
|
for (int j = 0; j < _sizeY; j++)
|
|
{
|
|
_density[i, j] = Math.Max(0, _density[i, j] - amount);
|
|
}
|
|
}
|
|
}
|
|
} |