You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

244 lines
5.6 KiB

#define NUM_THREADS 8
float4 _Size;
float _DeltaTime, _Dissipate, _Decay, _Forward;
StructuredBuffer<float3> _Velocity;
StructuredBuffer<float> _Obstacles;
RWStructuredBuffer<float> _Write1f;
StructuredBuffer<float> _Read1f;
RWStructuredBuffer<float3> _Write3f;
StructuredBuffer<float3> _Read3f;
StructuredBuffer<float> _Phi_n_1_hat, _Phi_n_hat;
float3 GetAdvectedPosTexCoords(float3 pos, int idx)
{
pos -= _DeltaTime * _Forward * _Velocity[idx];
return pos;
}
float SampleBilinear(StructuredBuffer<float> buffer, float3 uv, float3 size)
{
int x = uv.x;
int y = uv.y;
int z = uv.z;
int X = size.x;
int XY = size.x*size.y;
float fx = uv.x-x;
float fy = uv.y-y;
float fz = uv.z-z;
int xp1 = min(size.x-1, x+1);
int yp1 = min(size.y-1, y+1);
int zp1 = min(size.z-1, z+1);
float x0 = buffer[x+y*X+z*XY] * (1.0f-fx) + buffer[xp1+y*X+z*XY] * fx;
float x1 = buffer[x+y*X+zp1*XY] * (1.0f-fx) + buffer[xp1+y*X+zp1*XY] * fx;
float x2 = buffer[x+yp1*X+z*XY] * (1.0f-fx) + buffer[xp1+yp1*X+z*XY] * fx;
float x3 = buffer[x+yp1*X+zp1*XY] * (1.0f-fx) + buffer[xp1+yp1*X+zp1*XY] * fx;
float z0 = x0 * (1.0f-fz) + x1 * fz;
float z1 = x2 * (1.0f-fz) + x3 * fz;
return z0 * (1.0f-fy) + z1 * fy;
}
float3 SampleBilinear(StructuredBuffer<float3> buffer, float3 uv, float3 size)
{
int x = uv.x;
int y = uv.y;
int z = uv.z;
int X = size.x;
int XY = size.x*size.y;
float fx = uv.x-x;
float fy = uv.y-y;
float fz = uv.z-z;
int xp1 = min(size.x-1, x+1);
int yp1 = min(size.y-1, y+1);
int zp1 = min(size.z-1, z+1);
float3 x0 = buffer[x+y*X+z*XY] * (1.0f-fx) + buffer[xp1+y*X+z*XY] * fx;
float3 x1 = buffer[x+y*X+zp1*XY] * (1.0f-fx) + buffer[xp1+y*X+zp1*XY] * fx;
float3 x2 = buffer[x+yp1*X+z*XY] * (1.0f-fx) + buffer[xp1+yp1*X+z*XY] * fx;
float3 x3 = buffer[x+yp1*X+zp1*XY] * (1.0f-fx) + buffer[xp1+yp1*X+zp1*XY] * fx;
float3 z0 = x0 * (1.0f-fz) + x1 * fz;
float3 z1 = x2 * (1.0f-fz) + x3 * fz;
return z0 * (1.0f-fy) + z1 * fy;
}
#pragma kernel AdvectVelocity
[numthreads(NUM_THREADS,NUM_THREADS,NUM_THREADS)]
void AdvectVelocity(uint3 id : SV_DispatchThreadID)
{
int idx = id.x + id.y*_Size.x + id.z*_Size.x*_Size.y;
if(_Obstacles[idx] > 0.1)
{
_Write3f[idx] = float3(0,0,0);
return;
}
float3 uv = GetAdvectedPosTexCoords(id, idx);
_Write3f[idx] = SampleBilinear(_Read3f, uv, _Size.xyz) * _Dissipate;
}
#pragma kernel Advect
[numthreads(NUM_THREADS,NUM_THREADS,NUM_THREADS)]
void Advect(uint3 id : SV_DispatchThreadID)
{
int idx = id.x + id.y*_Size.x + id.z*_Size.x*_Size.y;
if(_Obstacles[idx] > 0.1)
{
_Write1f[idx] = 0;
return;
}
float3 uv = GetAdvectedPosTexCoords(id, idx);
_Write1f[idx] = max(0, SampleBilinear(_Read1f, uv, _Size.xyz) * _Dissipate - _Decay);
}
#pragma kernel AdvectBFECC
[numthreads(NUM_THREADS,NUM_THREADS,NUM_THREADS)]
void AdvectBFECC(uint3 id : SV_DispatchThreadID)
{
int idx = id.x + id.y*_Size.x + id.z*_Size.x*_Size.y;
if(_Obstacles[idx] > 0.1)
{
_Write1f[idx] = 0;
return;
}
float3 uv = GetAdvectedPosTexCoords(id, idx);
float r;
float4 halfVolumeDim = _Size/2;
float3 diff = abs( halfVolumeDim.xyz - id );
// Must use regular semi-Lagrangian advection instead of BFECC at the volume boundaries
if( (diff.x > (halfVolumeDim.x-4)) || (diff.y > (halfVolumeDim.y-4)) || (diff.z > (halfVolumeDim.z-4)) )
{
r = SampleBilinear(_Read1f, uv, _Size.xyz);
}
else
{
r = 1.5f * SampleBilinear(_Read1f, uv, _Size.xyz) - 0.5f * SampleBilinear(_Phi_n_hat, uv, _Size.xyz);
}
_Write1f[idx] = max(0, r * _Dissipate - _Decay);
}
#pragma kernel AdvectMacCormack
[numthreads(NUM_THREADS,NUM_THREADS,NUM_THREADS)]
void AdvectMacCormack(uint3 id : SV_DispatchThreadID)
{
int idx = id.x + id.y*_Size.x + id.z*_Size.x*_Size.y;
if(_Obstacles[idx] > 0.1)
{
_Write1f[idx] = 0;
return;
}
float3 uv = GetAdvectedPosTexCoords(id, idx);
float r;
float4 halfVolumeDim = _Size/2;
float3 diff = abs( halfVolumeDim.xyz - id );
// Must use regular semi-Lagrangian advection instead of MacCormack at the volume boundaries
if( (diff.x > (halfVolumeDim.x-4)) || (diff.y > (halfVolumeDim.y-4)) || (diff.z > (halfVolumeDim.z-4)) )
{
r = SampleBilinear(_Read1f, uv, _Size.xyz);
}
else
{
int idx0 = (id.x-1) + (id.y-1)*_Size.x + (id.z-1)*_Size.x*_Size.y;
int idx1 = (id.x-1) + (id.y-1)*_Size.x + (id.z+1)*_Size.x*_Size.y;
int idx2 = (id.x-1) + (id.y+1)*_Size.x + (id.z-1)*_Size.x*_Size.y;
int idx3 = (id.x-1) + (id.y+1)*_Size.x + (id.z+1)*_Size.x*_Size.y;
int idx4 = (id.x+1) + (id.y-1)*_Size.x + (id.z-1)*_Size.x*_Size.y;
int idx5 = (id.x+1) + (id.y-1)*_Size.x + (id.z+1)*_Size.x*_Size.y;
int idx6 = (id.x+1) + (id.y+1)*_Size.x + (id.z-1)*_Size.x*_Size.y;
int idx7 = (id.x+1) + (id.y+1)*_Size.x + (id.z+1)*_Size.x*_Size.y;
float nodes[8];
nodes[0] = _Read1f[ idx0 ];
nodes[1] = _Read1f[ idx1 ];
nodes[2] = _Read1f[ idx2 ];
nodes[3] = _Read1f[ idx3 ];
nodes[4] = _Read1f[ idx4 ];
nodes[5] = _Read1f[ idx5 ];
nodes[6] = _Read1f[ idx6 ];
nodes[7] = _Read1f[ idx7 ];
float minPhi = min(min(min(min(min(min(min(nodes[0],nodes[1]),nodes[2]),nodes[3]),nodes[4]),nodes[5]),nodes[6]),nodes[7]);
float maxPhi = max(max(max(max(max(max(max(nodes[0],nodes[1]),nodes[2]),nodes[3]),nodes[4]),nodes[5]),nodes[6]),nodes[7]);
r = SampleBilinear(_Phi_n_1_hat, uv, _Size.xyz) + 0.5f * (_Read1f[idx] - _Phi_n_hat[idx]);
r = max(min(r, maxPhi), minPhi);
}
_Write1f[idx] = max(0, r * _Dissipate - _Decay);
}