You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
333 lines
9.1 KiB
Plaintext
333 lines
9.1 KiB
Plaintext
#pragma kernel AddVelocity
|
|
#pragma kernel InitBoundaries
|
|
#pragma kernel AdvectVelocity
|
|
#pragma kernel Divergence
|
|
#pragma kernel ClearBuffer
|
|
#pragma kernel Poisson
|
|
#pragma kernel SubstractGradient
|
|
#pragma kernel CalcVorticity
|
|
#pragma kernel ApplyVorticity
|
|
#pragma kernel Viscosity
|
|
#pragma kernel AddCircleObstacle
|
|
#pragma kernel AddTriangleObstacle
|
|
|
|
#include "FLUID_DYNAMICS_MAIN.compute"
|
|
|
|
const uint2 _Size;
|
|
RWStructuredBuffer<float2> _VelocityIn;
|
|
RWStructuredBuffer<float2> _VelocityOut;
|
|
RWStructuredBuffer<float2> _Obstacles;
|
|
RWStructuredBuffer<float> _Divergence;
|
|
RWStructuredBuffer<float> _PressureIn;
|
|
RWStructuredBuffer<float> _PressureOut;
|
|
RWStructuredBuffer<float> _Vorticity;
|
|
|
|
float _ElapsedTime;
|
|
float _Speed;
|
|
float _Radius;
|
|
float2 _Position;
|
|
float2 _Value;
|
|
float _VorticityScale;
|
|
int _Static;
|
|
uint4 GetNeighbours(int2 pos, int2 size)
|
|
{
|
|
uint4 result;
|
|
const int maxX = size.x - 1;
|
|
const int maxY = size.y - 1;
|
|
|
|
result.x = pos.y*_Size.x + clamp(pos.x - 1, 0, maxX);
|
|
result.y = pos.y*_Size.x + clamp(pos.x + 1, 0, maxX);
|
|
result.z = clamp(pos.y - 1, 0, maxY)*size.x + pos.x;
|
|
result.w = clamp(pos.y + 1, 0, maxY)*size.x + pos.x;
|
|
return result;
|
|
}
|
|
// UTIL: Clear Buffer
|
|
RWStructuredBuffer<float2> _Buffer;
|
|
[numthreads(THREAD_COUNT, THREAD_COUNT, 1)]
|
|
void ClearBuffer(uint3 id : SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= _Size.x || id.y >= _Size.y) { return; }
|
|
uint pos = id.y*_Size.x + id.x;
|
|
_Buffer[pos].x = 0.0;
|
|
}
|
|
|
|
[numthreads(THREAD_COUNT, THREAD_COUNT, 1)]
|
|
void AddVelocity(uint3 id : SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= _Size.x || id.y >= _Size.y) { return; }
|
|
|
|
const uint pos = id.y*_Size.x + id.x;
|
|
const float2 splat_pos = _Position*_Size;
|
|
|
|
const float2 val = _VelocityIn[pos];
|
|
float2 result = val;
|
|
|
|
float len = distance(splat_pos, (float2) id);
|
|
if (len <= _Radius)
|
|
{
|
|
result = val + _Value*(_Radius - len) / _Radius;
|
|
}
|
|
|
|
_VelocityOut[pos] = clamp(result, float2(-1.0, -1.0), float2(1.0, 1.0));
|
|
}
|
|
|
|
[numthreads(THREAD_COUNT, THREAD_COUNT, 1)]
|
|
void InitBoundaries(uint3 id : SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= _Size.x || id.y >= _Size.y) { return; }
|
|
uint pos = id.y*_Size.x + id.x;
|
|
|
|
if (id.x == 0)
|
|
{
|
|
_VelocityIn[pos] = float2(0.0,0.0);
|
|
}
|
|
else if (id.x == _Size.x - 1)
|
|
{
|
|
_VelocityIn[pos] = float2(0.0, 0.0);
|
|
}
|
|
else if (id.y == 0)
|
|
{
|
|
_VelocityIn[pos] = float2(0.0, 0.0);
|
|
}
|
|
else if (id.y == _Size.y - 1)
|
|
{
|
|
_VelocityIn[pos] = float2(0.0, 0.0);
|
|
}
|
|
}
|
|
|
|
float _Dissipation;
|
|
[numthreads(THREAD_COUNT, THREAD_COUNT, 1)]
|
|
void AdvectVelocity(uint3 id : SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= _Size.x || id.y >= _Size.y) { return; }
|
|
const uint pos = id.y*_Size.x + id.x;
|
|
|
|
const float2 obstacle = _Obstacles[pos];
|
|
if (obstacle.x > 0.0 || obstacle.y > 0.0)
|
|
{
|
|
_VelocityOut[pos] = float2(0, 0);
|
|
}
|
|
else
|
|
{
|
|
const float2 vel = _VelocityIn[pos];
|
|
const float2 final_pos = float2(id.x - vel.x*_ElapsedTime*_Speed, id.y - vel.y*_ElapsedTime*_Speed);
|
|
|
|
const int2 zero = int2(0, 0);
|
|
const int2 SizeBounds = int2(_Size.x - 1, _Size.y - 1);
|
|
const int2 top_right = clamp(ceil(final_pos), zero, SizeBounds);
|
|
const int2 bottom_left = clamp(floor(final_pos), zero, SizeBounds);
|
|
|
|
const float2 delta = final_pos - bottom_left;
|
|
|
|
const float2 lt = _VelocityIn[top_right.y*_Size.x + bottom_left.x];
|
|
const float2 rt = _VelocityIn[top_right.y*_Size.x + top_right.x];
|
|
|
|
const float2 lb = _VelocityIn[bottom_left.y*_Size.x + bottom_left.x];
|
|
const float2 rb = _VelocityIn[bottom_left.y*_Size.x + top_right.x];
|
|
|
|
const float2 h1 = lerp(lt, rt, delta.x);
|
|
const float2 h2 = lerp(lb, rb, delta.x);
|
|
|
|
_VelocityOut[pos] = clamp(lerp(h2, h1, delta.y)*_Dissipation, float2(-1.0, -1.0), float2(1.0, 1.0));
|
|
}
|
|
}
|
|
|
|
[numthreads(THREAD_COUNT, THREAD_COUNT, 1)]
|
|
void Divergence(uint3 id : SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= _Size.x || id.y >= _Size.y) { return; }
|
|
const uint pos = id.y*_Size.x + id.x;
|
|
|
|
const uint4 n = GetNeighbours(id.xy, _Size);
|
|
|
|
float x1 = _VelocityIn[n.x].x;
|
|
float x2 = _VelocityIn[n.y].x;
|
|
float y1 = _VelocityIn[n.z].y;
|
|
float y2 = _VelocityIn[n.w].y;
|
|
|
|
const float2 obsL = _Obstacles[n.x];
|
|
const float2 obsR = _Obstacles[n.y];
|
|
const float2 obsB = _Obstacles[n.z];
|
|
const float2 obsT = _Obstacles[n.w];
|
|
|
|
if (obsL.x > 0.0 || obsL.y > 0.0) x1 = 0.0;
|
|
if (obsR.x > 0.0 || obsR.y > 0.0) x2 = 0.0;
|
|
if (obsB.x > 0.0 || obsB.y > 0.0) y1 = 0.0;
|
|
if (obsT.x > 0.0 || obsT.y > 0.0) y2 = 0.0;
|
|
|
|
_Divergence[pos] = 0.5f * ((x2 - x1) + (y2 - y1));
|
|
}
|
|
|
|
[numthreads(THREAD_COUNT, THREAD_COUNT, 1)]
|
|
void Poisson(uint3 id : SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= _Size.x || id.y >= _Size.y) { return; }
|
|
const uint pos = id.y*_Size.x + id.x;
|
|
|
|
//const float alpha = -1.0f;
|
|
const float rbeta = 0.25;
|
|
|
|
const uint4 n = GetNeighbours(id.xy, _Size);
|
|
|
|
float p = _PressureIn[pos];
|
|
|
|
|
|
const float2 obsL = _Obstacles[n.x];
|
|
const float2 obsR = _Obstacles[n.y];
|
|
const float2 obsB = _Obstacles[n.z];
|
|
const float2 obsT = _Obstacles[n.w];
|
|
|
|
const float x1 = (obsL.x > 0.0 || obsL.y > 0.0) ? p : _PressureIn[n.x];
|
|
const float x2 = (obsR.x > 0.0 || obsR.y > 0.0) ? p : _PressureIn[n.y];
|
|
const float y1 = (obsB.x > 0.0 || obsB.y > 0.0) ? p : _PressureIn[n.z];
|
|
const float y2 = (obsT.x > 0.0 || obsT.y > 0.0) ? p : _PressureIn[n.w];
|
|
|
|
const float b = _Divergence[pos];
|
|
|
|
_PressureOut[pos] = (x1 + x2 + y1 + y2 - b) * rbeta;
|
|
}
|
|
|
|
[numthreads(THREAD_COUNT, THREAD_COUNT, 1)]
|
|
void SubstractGradient(uint3 id : SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= _Size.x || id.y >= _Size.y) { return; }
|
|
|
|
const uint4 n = GetNeighbours(id.xy, _Size);
|
|
|
|
const uint pos = id.y*_Size.x + id.x;
|
|
float x1 = _PressureIn[n.x];
|
|
float x2 = _PressureIn[n.y];
|
|
float y1 = _PressureIn[n.z];
|
|
float y2 = _PressureIn[n.w];
|
|
float p = _PressureIn[pos];
|
|
|
|
const float2 obsL = _Obstacles[n.x];
|
|
const float2 obsR = _Obstacles[n.y];
|
|
const float2 obsB = _Obstacles[n.z];
|
|
const float2 obsT = _Obstacles[n.w];
|
|
|
|
if (obsL.x > 0.0 || obsL.y > 0.0) x1 = p;
|
|
if (obsR.x > 0.0 || obsR.y > 0.0) x2 = p;
|
|
if (obsB.x > 0.0 || obsB.y > 0.0) y1 = p;
|
|
if (obsT.x > 0.0 || obsT.y > 0.0) y2 = p;
|
|
|
|
float2 velocity = _VelocityIn[pos];
|
|
velocity.x -= 0.5f * (x2 - x1);
|
|
velocity.y -= 0.5f * (y2 - y1);
|
|
_VelocityOut[pos] = velocity;
|
|
}
|
|
|
|
[numthreads(THREAD_COUNT, THREAD_COUNT, 1)]
|
|
void CalcVorticity(uint3 id : SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= _Size.x || id.y >= _Size.y) { return; }
|
|
const uint pos = id.y*_Size.x + id.x;
|
|
const uint4 n = GetNeighbours(id.xy, _Size);
|
|
|
|
const float2 vL = _VelocityIn[n.x];
|
|
const float2 vR = _VelocityIn[n.y];
|
|
const float2 vB = _VelocityIn[n.z];
|
|
const float2 vT = _VelocityIn[n.w];
|
|
|
|
_Vorticity[pos] = 0.5 * ((vR.y - vL.y) - (vT.x - vB.x));
|
|
}
|
|
|
|
[numthreads(THREAD_COUNT, THREAD_COUNT, 1)]
|
|
void ApplyVorticity(uint3 id : SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= _Size.x || id.y >= _Size.y) { return; }
|
|
uint pos = id.y*_Size.x + id.x;
|
|
|
|
uint4 n = GetNeighbours(id.xy, _Size);
|
|
|
|
float vL = _Vorticity[n.x];
|
|
float vR = _Vorticity[n.y];
|
|
float vB = _Vorticity[n.z];
|
|
float vT = _Vorticity[n.w];
|
|
float vC = _Vorticity[pos];
|
|
|
|
float2 force = 0.5 * float2(abs(vT) - abs(vB), abs(vR) - abs(vL));
|
|
|
|
float EPSILON = 2.4414e-4;
|
|
float magSqr = max(EPSILON, dot(force, force));
|
|
force = force * rsqrt(magSqr);
|
|
|
|
force *= _VorticityScale * vC * float2(1, -1);
|
|
float2 final_force = force * _ElapsedTime;
|
|
|
|
_VelocityOut[pos] = _VelocityIn[pos] + float2(final_force.x, final_force.y);
|
|
}
|
|
|
|
float _Alpha;
|
|
float _rBeta;
|
|
[numthreads(THREAD_COUNT, THREAD_COUNT, 1)]
|
|
void Viscosity(uint3 id : SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= _Size.x || id.y >= _Size.y) { return; }
|
|
const uint pos = id.y*_Size.x + id.x;
|
|
const uint4 n = GetNeighbours(id.xy, _Size);
|
|
|
|
const float2 x1 = _VelocityIn[n.x];
|
|
const float2 x2 = _VelocityIn[n.y];
|
|
const float2 y1 = _VelocityIn[n.z];
|
|
const float2 y2 = _VelocityIn[n.w];
|
|
const float2 b = _VelocityIn[pos];
|
|
|
|
_VelocityOut[pos] = (x1 + x2 + y1 + y2 + b * _Alpha) * _rBeta;
|
|
}
|
|
|
|
[numthreads(THREAD_COUNT, THREAD_COUNT, 1)]
|
|
void AddCircleObstacle(uint3 id : SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= _Size.x || id.y >= _Size.y) { return; }
|
|
|
|
const uint pos = id.y*_Size.x + id.x;
|
|
const float2 splat_pos = _Position*_Size;
|
|
|
|
if (distance(splat_pos, (float2) id) <= _Radius)
|
|
{
|
|
if (_Static > 0)
|
|
{
|
|
_Obstacles[pos].y = 1.0;
|
|
}
|
|
else
|
|
{
|
|
_Obstacles[pos].x = 1.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
float2 _P1;
|
|
float2 _P2;
|
|
float2 _P3;
|
|
float Sign(float2 p1, float2 p2, float2 p3)
|
|
{
|
|
return ((p1.x - p3.x) * (p2.y - p3.y)) - ((p2.x - p3.x) * (p1.y - p3.y));
|
|
}
|
|
|
|
bool IsPointInTriangle(float2 pt, float2 v1, float2 v2, float2 v3)
|
|
{
|
|
const bool b1 = Sign(pt, v1, v2) < 0.0f;
|
|
const bool b2 = Sign(pt, v2, v3) < 0.0f;
|
|
const bool b3 = Sign(pt, v3, v1) < 0.0f;
|
|
return (b1 == b2) && (b2 == b3);
|
|
}
|
|
|
|
[numthreads(THREAD_COUNT, THREAD_COUNT, 1)]
|
|
void AddTriangleObstacle(uint3 id : SV_DispatchThreadID)
|
|
{
|
|
if (id.x >= _Size.x || id.y >= _Size.y) { return; }
|
|
const float2 pt = float2(id.x, id.y) / float2(_Size);
|
|
if (IsPointInTriangle(pt, _P1, _P2, _P3))
|
|
{
|
|
const uint pos = id.y*_Size.x + id.x;
|
|
if (_Static > 0)
|
|
{
|
|
_Obstacles[pos].y = 1.0;
|
|
}
|
|
else
|
|
{
|
|
_Obstacles[pos].x = 1.0;
|
|
}
|
|
}
|
|
} |