Compare commits
1
Commits
495e683522
...
424dea0012
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
424dea0012 |
@@ -0,0 +1,35 @@
|
||||
import FluidGridData;
|
||||
|
||||
struct Params
|
||||
{
|
||||
// read-write: phi to add source to
|
||||
FluidGridData<float> phi;
|
||||
FluidGridData<float> density;
|
||||
};
|
||||
ParameterBlock<Params> params;
|
||||
|
||||
[shader("compute")]
|
||||
[numthreads(32, 8, 1)]
|
||||
void addSource(uint3 dispatchThreadID : SV_DispatchThreadID)
|
||||
{
|
||||
FluidGridData<float> phi = params.phi;
|
||||
FluidGridData<float> density = params.density;
|
||||
int x = dispatchThreadID.x + 1;
|
||||
int y = dispatchThreadID.y + 1;
|
||||
int z = dispatchThreadID.z + 1;
|
||||
if(x >= gridParams.gridSize.x - 1 || y >= gridParams.gridSize.y - 1 || z >= gridParams.gridSize.z - 1) return;
|
||||
|
||||
// Add a spherical source and union it into the existing level set.
|
||||
float3 center = float3(gridParams.gridSize) * 0.5f;
|
||||
float radius = min(gridParams.gridSize.x, min(gridParams.gridSize.y, gridParams.gridSize.z)) * 0.25f;
|
||||
float3 pos = float3(x, y, z);
|
||||
float dist = length(pos - center);
|
||||
float sourcePhi = dist - radius;
|
||||
phi[x, y, z] = min(phi[x, y, z], sourcePhi);
|
||||
|
||||
if (sourcePhi < 0.0f)
|
||||
{
|
||||
density[x, y, z] += 0.5f;
|
||||
density[x, y, z] = min(density[x, y, z], 1.0f);
|
||||
}
|
||||
}
|
||||
@@ -30,16 +30,16 @@ void advect(uint3 dispatchThreadID : SV_DispatchThreadID)
|
||||
int x = dispatchThreadID.x + 1;
|
||||
int y = dispatchThreadID.y + 1;
|
||||
int z = dispatchThreadID.z + 1;
|
||||
if(x >= gridSize.x - 1 || y >= gridSize.y - 1 || z >= gridSize.z - 1) return;
|
||||
if(x >= gridParams.gridSize.x - 1 || y >= gridParams.gridSize.y - 1 || z >= gridParams.gridSize.z - 1) return;
|
||||
|
||||
float dt0x = dt * (gridSize.x - 2);
|
||||
float dt0y = dt * (gridSize.y - 2);
|
||||
float dt0z = dt * (gridSize.z - 2);
|
||||
float dt0x = dt * (gridParams.gridSize.x - 2);
|
||||
float dt0y = dt * (gridParams.gridSize.y - 2);
|
||||
float dt0z = dt * (gridParams.gridSize.z - 2);
|
||||
|
||||
float3 pos = float3(x - dt0x * velocityX[x, y, z], y - dt0y * velocityY[x, y, z], z - dt0z * velocityZ[x, y, z]);
|
||||
pos.x = clamp(pos.x, 0.5f, gridSize.x - 1.5f);
|
||||
pos.y = clamp(pos.y, 0.5f, gridSize.y - 1.5f);
|
||||
pos.z = clamp(pos.z, 0.5f, gridSize.z - 1.5f);
|
||||
pos.x = clamp(pos.x, 0.5f, gridParams.gridSize.x - 1.5f);
|
||||
pos.y = clamp(pos.y, 0.5f, gridParams.gridSize.y - 1.5f);
|
||||
pos.z = clamp(pos.z, 0.5f, gridParams.gridSize.z - 1.5f);
|
||||
|
||||
int3 i0 = int3(pos);
|
||||
int3 i1 = i0 + int3(1, 1, 1);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import FluidGridData;
|
||||
|
||||
struct Params
|
||||
{
|
||||
FluidGridData<float> velocityX;
|
||||
FluidGridData<float> velocityY;
|
||||
FluidGridData<float> velocityZ;
|
||||
float3 force;
|
||||
float dt;
|
||||
};
|
||||
ParameterBlock<Params> params;
|
||||
|
||||
[shader("compute")]
|
||||
[numthreads(32, 8, 1)]
|
||||
void applyForces(uint3 dispatchThreadID : SV_DispatchThreadID)
|
||||
{
|
||||
FluidGridData<float> velocityX = params.velocityX;
|
||||
FluidGridData<float> velocityY = params.velocityY;
|
||||
FluidGridData<float> velocityZ = params.velocityZ;
|
||||
float3 force = params.force;
|
||||
float dt = params.dt;
|
||||
|
||||
int x = dispatchThreadID.x + 1;
|
||||
int y = dispatchThreadID.y + 1;
|
||||
int z = dispatchThreadID.z + 1;
|
||||
if(x >= gridParams.gridSize.x - 1 || y >= gridParams.gridSize.y - 1 || z >= gridParams.gridSize.z - 1) return;
|
||||
|
||||
velocityX[x, y, z] += force.x * dt;
|
||||
velocityY[x, y, z] += force.y * dt;
|
||||
velocityZ[x, y, z] += force.z * dt;
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import FluidGridData;
|
||||
|
||||
struct Params
|
||||
{
|
||||
struct Params {
|
||||
// read-only
|
||||
FluidGridData<float> velocityX;
|
||||
// read-only
|
||||
@@ -17,8 +16,7 @@ ParameterBlock<Params> params;
|
||||
|
||||
[shader("compute")]
|
||||
[numthreads(32, 8, 1)]
|
||||
void computeDivergence(uint3 dispatchThreadID : SV_DispatchThreadID)
|
||||
{
|
||||
void computeDivergence(uint3 dispatchThreadID: SV_DispatchThreadID) {
|
||||
FluidGridData<float> velocityX = params.velocityX;
|
||||
FluidGridData<float> velocityY = params.velocityY;
|
||||
FluidGridData<float> velocityZ = params.velocityZ;
|
||||
@@ -28,8 +26,9 @@ void computeDivergence(uint3 dispatchThreadID : SV_DispatchThreadID)
|
||||
int x = dispatchThreadID.x + 1;
|
||||
int y = dispatchThreadID.y + 1;
|
||||
int z = dispatchThreadID.z + 1;
|
||||
if(x >= gridSize.x - 1 || y >= gridSize.y - 1 || z >= gridSize.z - 1) return;
|
||||
if (x >= gridParams.gridSize.x - 1 || y >= gridParams.gridSize.y - 1 || z >= gridParams.gridSize.z - 1)
|
||||
return;
|
||||
|
||||
divergence[x, y, z] = -0.5f * (velocityX[x + 1, y, z] - velocityX[x - 1, y, z] + velocityY[x, y + 1, z] - velocityY[x, y - 1, z] + velocityZ[x, y, z + 1] - velocityZ[x, y, z - 1]) / gridSize.x;
|
||||
divergence[x, y, z] = -0.5f * (velocityX[x + 1, y, z] - velocityX[x - 1, y, z] + velocityY[x, y + 1, z] - velocityY[x, y - 1, z] + velocityZ[x, y, z + 1] - velocityZ[x, y, z - 1]);
|
||||
pressure[x, y, z] = 0;
|
||||
}
|
||||
@@ -13,7 +13,7 @@ ParameterBlock<Parameter> params;
|
||||
|
||||
float getDensity(uint x, uint y, uint z)
|
||||
{
|
||||
return params.density[x + gridSize.x * y + gridSize.x * gridSize.y * z];
|
||||
return params.density[x + gridParams.gridSize.x * y + gridParams.gridSize.x * gridParams.gridSize.y * z];
|
||||
}
|
||||
|
||||
[shader("compute")]
|
||||
@@ -24,7 +24,7 @@ void main(uint3 dispatchThreadID : SV_DispatchThreadID)
|
||||
uint y = dispatchThreadID.y+1;
|
||||
uint z = dispatchThreadID.z+1;
|
||||
FluidGridData<float> density = params.density;
|
||||
if(x >= gridSize.x-3 || y >= gridSize.y-3 || z >= gridSize.z-3) return;
|
||||
if(x >= gridParams.gridSize.x-3 || y >= gridParams.gridSize.y-3 || z >= gridParams.gridSize.z-3) return;
|
||||
|
||||
float phi[8] = {
|
||||
getDensity(x, y, z),
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
static const uint3 gridSize = uint3(256, 256, 256);
|
||||
struct GridParams
|
||||
{
|
||||
uint3 gridSize;
|
||||
};
|
||||
ParameterBlock<GridParams> gridParams;
|
||||
struct FluidGridData<T>
|
||||
{
|
||||
RWStructuredBuffer<T> dataGrid;
|
||||
__subscript(uint3 index) -> T
|
||||
{
|
||||
get { return dataGrid[index.x + index.y * gridSize.x + index.z * gridSize.x * gridSize.y]; }
|
||||
set { dataGrid[index.x + index.y * gridSize.x + index.z * gridSize.x * gridSize.y] = newValue; }
|
||||
get { return dataGrid[index.x + index.y * gridParams.gridSize.x + index.z * gridParams.gridSize.x * gridParams.gridSize.y]; }
|
||||
set { dataGrid[index.x + index.y * gridParams.gridSize.x + index.z * gridParams.gridSize.x * gridParams.gridSize.y] = newValue; }
|
||||
}
|
||||
__subscript(uint x, uint y, uint z) -> T
|
||||
{
|
||||
get { return dataGrid[x + y * gridSize.x + z * gridSize.x * gridSize.y]; }
|
||||
set { dataGrid[x + y * gridSize.x + z * gridSize.x * gridSize.y] = newValue; }
|
||||
get { return dataGrid[x + y * gridParams.gridSize.x + z * gridParams.gridSize.x * gridParams.gridSize.y]; }
|
||||
set { dataGrid[x + y * gridParams.gridSize.x + z * gridParams.gridSize.x * gridParams.gridSize.y] = newValue; }
|
||||
}
|
||||
};
|
||||
|
||||
@@ -26,7 +26,7 @@ void linearSolve(uint3 dispatchThreadID : SV_DispatchThreadID)
|
||||
int x = dispatchThreadID.x + 1;
|
||||
int y = dispatchThreadID.y + 1;
|
||||
int z = dispatchThreadID.z + 1;
|
||||
if(x >= gridSize.x - 1 || y >= gridSize.y - 1 || z >= gridSize.z - 1) return;
|
||||
if(x >= gridParams.gridSize.x - 1 || y >= gridParams.gridSize.y - 1 || z >= gridParams.gridSize.z - 1) return;
|
||||
|
||||
next[x, y, z] = (grid0[x, y, z] + a * (current[x + 1, y, z] + current[x - 1, y, z] + current[x, y + 1, z] + current[x, y - 1, z] + current[x, y, z + 1] + current[x, y, z - 1])) * cRecip;
|
||||
}
|
||||
@@ -12,7 +12,7 @@ struct Params
|
||||
ParameterBlock<Params> params;
|
||||
|
||||
const static float isoLevel = 0.0f;
|
||||
const static float3 cellSize = 1.0f / gridSize;
|
||||
const static float3 cellSize = 1.0f / gridParams.gridSize;
|
||||
|
||||
float3 vertexInterp(float isoLevel, float3 p1, float3 p2, float valp1, float valp2)
|
||||
{
|
||||
@@ -86,7 +86,7 @@ void marchingCubes(uint3 dispatchThreadID : SV_DispatchThreadID, uint groupIndex
|
||||
|
||||
// Don't early-return — all threads must participate in barriers.
|
||||
// Use a flag to skip work for out-of-bounds threads.
|
||||
bool valid = (x < gridSize.x - 2 && y < gridSize.y - 2 && z < gridSize.z - 2);
|
||||
bool valid = (x < gridParams.gridSize.x - 2 && y < gridParams.gridSize.y - 2 && z < gridParams.gridSize.z - 2);
|
||||
|
||||
float val[8];
|
||||
uint cubeIndex = 0;
|
||||
@@ -169,7 +169,7 @@ void marchingCubes(uint3 dispatchThreadID : SV_DispatchThreadID, uint groupIndex
|
||||
float3 v0 = vertList[triTable[cubeIndex][i]];
|
||||
float3 v1 = vertList[triTable[cubeIndex][i + 1]];
|
||||
float3 v2 = vertList[triTable[cubeIndex][i + 2]];
|
||||
float3 n = normalize(cross(v1 - v0, v2 - v0));
|
||||
float3 n = normalize(cross(v2 - v0, v1 - v0));
|
||||
|
||||
localVertices[localOff] = v0;
|
||||
localVertices[localOff + 1] = v1;
|
||||
|
||||
@@ -25,9 +25,9 @@ void project(uint3 dispatchThreadID : SV_DispatchThreadID)
|
||||
int x = dispatchThreadID.x + 1;
|
||||
int y = dispatchThreadID.y + 1;
|
||||
int z = dispatchThreadID.z + 1;
|
||||
if(x >= gridSize.x - 1 || y >= gridSize.y - 1 || z >= gridSize.z - 1) return;
|
||||
if(x >= gridParams.gridSize.x - 1 || y >= gridParams.gridSize.y - 1 || z >= gridParams.gridSize.z - 1) return;
|
||||
|
||||
velocityX[x, y, z] -= 0.5f * (pressure[x + 1, y, z] - pressure[x - 1, y, z]) * gridSize.x;
|
||||
velocityY[x, y, z] -= 0.5f * (pressure[x, y + 1, z] - pressure[x, y - 1, z]) * gridSize.y;
|
||||
velocityZ[x, y, z] -= 0.5f * (pressure[x, y, z + 1] - pressure[x, y, z - 1]) * gridSize.z;
|
||||
velocityX[x, y, z] -= 0.5f * (pressure[x + 1, y, z] - pressure[x - 1, y, z]);
|
||||
velocityY[x, y, z] -= 0.5f * (pressure[x, y + 1, z] - pressure[x, y - 1, z]);
|
||||
velocityZ[x, y, z] -= 0.5f * (pressure[x, y, z + 1] - pressure[x, y, z - 1]);
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import MaterialParameter;
|
||||
|
||||
struct Params
|
||||
{
|
||||
float4x4 transform;
|
||||
StructuredBuffer<float> vertexBuffer;
|
||||
StructuredBuffer<float> normalBuffer;
|
||||
StructuredBuffer<uint> indexBuffer;
|
||||
@@ -25,10 +26,12 @@ VertexOut vertexMain(uint vertexId : SV_VertexID)
|
||||
uint index = params.indexBuffer[vertexId];
|
||||
float3 vertex = float3(params.vertexBuffer[index * 3 + 0],
|
||||
params.vertexBuffer[index * 3 + 1],
|
||||
params.vertexBuffer[index * 3 + 2]) * 5;
|
||||
params.vertexBuffer[index * 3 + 2]);
|
||||
float3 normal = float3(params.normalBuffer[index * 3 + 0],
|
||||
params.normalBuffer[index * 3 + 1],
|
||||
params.normalBuffer[index * 3 + 2]);
|
||||
vertex = mul(params.transform, float4(vertex, 1)).xyz;
|
||||
normal = mul((float3x3)params.transform, normal);
|
||||
output.position_WS = vertex;
|
||||
output.position_CS = mul(pViewParams.viewProjectionMatrix, float4(vertex, 1));
|
||||
output.normal = normal;
|
||||
|
||||
@@ -14,18 +14,29 @@ void setBound(uint3 dispatchThreadID : SV_DispatchThreadID)
|
||||
{
|
||||
int b = params.b;
|
||||
FluidGridData<float> grid = params.grid;
|
||||
int x = dispatchThreadID.x + 1;
|
||||
int y = dispatchThreadID.y + 1;
|
||||
if(x >= gridSize.x - 1 || y >= gridSize.y - 1) return;
|
||||
int i = dispatchThreadID.x + 1;
|
||||
int j = dispatchThreadID.y + 1;
|
||||
|
||||
grid[0, x, y] = b == 1 ? -grid[1, x, y] : grid[1, x, y];
|
||||
grid[gridSize.x - 1, x, y] = b == 1 ? -grid[gridSize.x - 2, x, y] : grid[gridSize.x - 2, x, y];
|
||||
// X-faces: indices range over (gridSize.y, gridSize.z)
|
||||
if(i < gridParams.gridSize.y - 1 && j < gridParams.gridSize.z - 1)
|
||||
{
|
||||
grid[0, i, j] = b == 1 ? -grid[1, i, j] : grid[1, i, j];
|
||||
grid[gridParams.gridSize.x - 1, i, j] = b == 1 ? -grid[gridParams.gridSize.x - 2, i, j] : grid[gridParams.gridSize.x - 2, i, j];
|
||||
}
|
||||
|
||||
grid[x, 0, y] = b == 2 ? -grid[x, 1, y] : grid[x, 1, y];
|
||||
grid[x, gridSize.y - 1, y] = b == 2 ? -grid[x, gridSize.y - 2, y] : grid[x, gridSize.y - 2, y];
|
||||
// Y-faces: indices range over (gridSize.x, gridSize.z)
|
||||
if(i < gridParams.gridSize.x - 1 && j < gridParams.gridSize.z - 1)
|
||||
{
|
||||
grid[i, 0, j] = b == 2 ? -grid[i, 1, j] : grid[i, 1, j];
|
||||
grid[i, gridParams.gridSize.y - 1, j] = b == 2 ? -grid[i, gridParams.gridSize.y - 2, j] : grid[i, gridParams.gridSize.y - 2, j];
|
||||
}
|
||||
|
||||
grid[x, y, 0] = b == 3 ? -grid[x, y, 1] : grid[x, y, 1];
|
||||
grid[x, y, gridSize.z - 1] = b == 3 ? -grid[x, y, gridSize.z - 2] : grid[x, y, gridSize.z - 2];
|
||||
// Z-faces: indices range over (gridSize.x, gridSize.y)
|
||||
if(i < gridParams.gridSize.x - 1 && j < gridParams.gridSize.y - 1)
|
||||
{
|
||||
grid[i, j, 0] = b == 3 ? -grid[i, j, 1] : grid[i, j, 1];
|
||||
grid[i, j, gridParams.gridSize.z - 1] = b == 3 ? -grid[i, j, gridParams.gridSize.z - 2] : grid[i, j, gridParams.gridSize.z - 2];
|
||||
}
|
||||
}
|
||||
|
||||
[shader("compute")]
|
||||
@@ -34,22 +45,33 @@ void setBoundEdges(uint3 dispatchThreadID : SV_DispatchThreadID)
|
||||
{
|
||||
FluidGridData<float> grid = params.grid;
|
||||
int x = dispatchThreadID.x + 1;
|
||||
if(x >= gridSize.x - 1) return;
|
||||
|
||||
// X-axis edges: x ranges [1, gridSize.x-2]
|
||||
if(x < gridParams.gridSize.x - 1)
|
||||
{
|
||||
grid[x, 0, 0] = 0.5f * (grid[x, 1, 0] + grid[x, 0, 1]);
|
||||
grid[x, gridSize.y - 1, 0] = 0.5f * (grid[x, gridSize.y - 2, 0] + grid[x, gridSize.y - 1, 1]);
|
||||
grid[x, 0, gridSize.z - 1] = 0.5f * (grid[x, 1, gridSize.z - 1] + grid[x, 0, gridSize.z - 2]);
|
||||
grid[x, gridSize.y - 1, gridSize.z - 1] = 0.5f * (grid[x, gridSize.y - 2, gridSize.z - 1] + grid[x, gridSize.y - 1, gridSize.z - 2]);
|
||||
grid[x, gridParams.gridSize.y - 1, 0] = 0.5f * (grid[x, gridParams.gridSize.y - 2, 0] + grid[x, gridParams.gridSize.y - 1, 1]);
|
||||
grid[x, 0, gridParams.gridSize.z - 1] = 0.5f * (grid[x, 1, gridParams.gridSize.z - 1] + grid[x, 0, gridParams.gridSize.z - 2]);
|
||||
grid[x, gridParams.gridSize.y - 1, gridParams.gridSize.z - 1] = 0.5f * (grid[x, gridParams.gridSize.y - 2, gridParams.gridSize.z - 1] + grid[x, gridParams.gridSize.y - 1, gridParams.gridSize.z - 2]);
|
||||
}
|
||||
|
||||
// Y-axis edges: x ranges [1, gridSize.y-2]
|
||||
if(x < gridParams.gridSize.y - 1)
|
||||
{
|
||||
grid[0, x, 0] = 0.5f * (grid[1, x, 0] + grid[0, x, 1]);
|
||||
grid[0, x, gridSize.z - 1] = 0.5f * (grid[1, x, gridSize.z - 1] + grid[0, x, gridSize.z - 2]);
|
||||
grid[gridSize.x - 1, x, 0] = 0.5f * (grid[gridSize.x - 2, x, 0] + grid[gridSize.x - 1, x, 1]);
|
||||
grid[gridSize.x - 1, x, gridSize.z - 1] = 0.5f * (grid[gridSize.x - 2, x, gridSize.z - 1] + grid[gridSize.x - 1, x, gridSize.z - 2]);
|
||||
grid[0, x, gridParams.gridSize.z - 1] = 0.5f * (grid[1, x, gridParams.gridSize.z - 1] + grid[0, x, gridParams.gridSize.z - 2]);
|
||||
grid[gridParams.gridSize.x - 1, x, 0] = 0.5f * (grid[gridParams.gridSize.x - 2, x, 0] + grid[gridParams.gridSize.x - 1, x, 1]);
|
||||
grid[gridParams.gridSize.x - 1, x, gridParams.gridSize.z - 1] = 0.5f * (grid[gridParams.gridSize.x - 2, x, gridParams.gridSize.z - 1] + grid[gridParams.gridSize.x - 1, x, gridParams.gridSize.z - 2]);
|
||||
}
|
||||
|
||||
// Z-axis edges: x ranges [1, gridSize.z-2]
|
||||
if(x < gridParams.gridSize.z - 1)
|
||||
{
|
||||
grid[0, 0, x] = 0.5f * (grid[1, 0, x] + grid[0, 1, x]);
|
||||
grid[0, gridSize.y - 1, x] = 0.5f * (grid[1, gridSize.y - 1, x] + grid[0, gridSize.y - 2, x]);
|
||||
grid[gridSize.x - 1, 0, x] = 0.5f * (grid[gridSize.x - 2, 0, x] + grid[gridSize.x - 1, 1, x]);
|
||||
grid[gridSize.x - 1, gridSize.y - 1, x] = 0.5f * (grid[gridSize.x - 2, gridSize.y - 1, x] + grid[gridSize.x - 1, gridSize.y - 2, x]);
|
||||
grid[0, gridParams.gridSize.y - 1, x] = 0.5f * (grid[1, gridParams.gridSize.y - 1, x] + grid[0, gridParams.gridSize.y - 2, x]);
|
||||
grid[gridParams.gridSize.x - 1, 0, x] = 0.5f * (grid[gridParams.gridSize.x - 2, 0, x] + grid[gridParams.gridSize.x - 1, 1, x]);
|
||||
grid[gridParams.gridSize.x - 1, gridParams.gridSize.y - 1, x] = 0.5f * (grid[gridParams.gridSize.x - 2, gridParams.gridSize.y - 1, x] + grid[gridParams.gridSize.x - 1, gridParams.gridSize.y - 2, x]);
|
||||
}
|
||||
}
|
||||
|
||||
[shader("compute")]
|
||||
@@ -59,13 +81,13 @@ void setBoundCorners(uint3 dispatchThreadID : SV_DispatchThreadID)
|
||||
FluidGridData<float> grid = params.grid;
|
||||
uint threadIdx = dispatchThreadID.x;
|
||||
|
||||
uint x = ((threadIdx & 1) == 0) ? 0 : (gridSize.x - 1);
|
||||
uint y = ((threadIdx & 2) == 0) ? 0 : (gridSize.y - 1);
|
||||
uint z = ((threadIdx & 4) == 0) ? 0 : (gridSize.z - 1);
|
||||
uint x = ((threadIdx & 1) == 0) ? 0 : (gridParams.gridSize.x - 1);
|
||||
uint y = ((threadIdx & 2) == 0) ? 0 : (gridParams.gridSize.y - 1);
|
||||
uint z = ((threadIdx & 4) == 0) ? 0 : (gridParams.gridSize.z - 1);
|
||||
|
||||
uint nx = (x == 0) ? 1 : (gridSize.x - 2);
|
||||
uint ny = (y == 0) ? 1 : (gridSize.y - 2);
|
||||
uint nz = (z == 0) ? 1 : (gridSize.z - 2);
|
||||
uint nx = (x == 0) ? 1 : (gridParams.gridSize.x - 2);
|
||||
uint ny = (y == 0) ? 1 : (gridParams.gridSize.y - 2);
|
||||
uint nz = (z == 0) ? 1 : (gridParams.gridSize.z - 2);
|
||||
|
||||
grid[x, y, z] = 0.33f * (grid[nx, y, z] + grid[x, ny, z] + grid[x, y, nz]);
|
||||
grid[x, y, z] = (1.0f / 3.0f) * (grid[nx, y, z] + grid[x, ny, z] + grid[x, y, nz]);
|
||||
}
|
||||
@@ -25,7 +25,7 @@ void reinitialize(uint3 dispatchThreadID : SV_DispatchThreadID)
|
||||
uint z = dispatchThreadID.z + 1;
|
||||
FluidGridData<float> phi = params.phi;
|
||||
FluidGridData<float> phi0 = params.phi0;
|
||||
if(x >= gridSize.x - 1 || y >= gridSize.y - 1 || z >= gridSize.z - 1) return;
|
||||
if(x >= gridParams.gridSize.x - 1 || y >= gridParams.gridSize.y - 1 || z >= gridParams.gridSize.z - 1) return;
|
||||
|
||||
float dtau = params.dtau;
|
||||
float dx = 1.0f;
|
||||
|
||||
@@ -4,10 +4,13 @@
|
||||
namespace Seele {
|
||||
namespace Component {
|
||||
struct FluidGrid {
|
||||
float cellSize = 1.0f;
|
||||
float viscosity = 0.1f;
|
||||
float diffusion = 0.01f;
|
||||
bool paused = true;
|
||||
float dt = 0.1f;
|
||||
float viscosity = 0.001f;
|
||||
float diffusion = 0.0001f;
|
||||
UVector gridSize = {128, 128, 128};
|
||||
Vector gravity = {0.0f, -9.81f, 0.0f};
|
||||
bool enableGravity = true;
|
||||
};
|
||||
} // namespace Component
|
||||
} // namespace Seele
|
||||
@@ -1,19 +1,26 @@
|
||||
#include "FluidRenderPass.h"
|
||||
#include "Component/Transform.h"
|
||||
#include "Graphics/Command.h"
|
||||
#include "Graphics/Descriptor.h"
|
||||
#include "Graphics/Enums.h"
|
||||
#include "Graphics/Graphics.h"
|
||||
#include "Graphics/Initializer.h"
|
||||
#include "Graphics/RenderTarget.h"
|
||||
#include "Graphics/Shader.h"
|
||||
#include "Math/Matrix.h"
|
||||
#include "Scene/LightEnvironment.h"
|
||||
#include "Scene/Scene.h"
|
||||
#include "Scene/FluidScene.h"
|
||||
|
||||
using namespace Seele;
|
||||
|
||||
FluidRenderPass::FluidRenderPass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graphics), scene(scene) {
|
||||
pipelineLayout = graphics->createPipelineLayout("FluidPipelineLayout");
|
||||
descriptorLayout = graphics->createDescriptorLayout("params");
|
||||
descriptorLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||
.name = "transform",
|
||||
.uniformLength = sizeof(Matrix4),
|
||||
});
|
||||
descriptorLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||
.name = "vertexBuffer",
|
||||
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
@@ -54,6 +61,8 @@ void FluidRenderPass::render() {
|
||||
descriptorLayout->reset();
|
||||
for (const auto& [id, data] : scene->getFluidScene()->getFluidDataMap()) {
|
||||
descriptorSet = descriptorLayout->allocateDescriptorSet();
|
||||
Matrix4 transformMatrix = data.transform.toMatrix();
|
||||
descriptorSet->updateConstants("transform", 0, &transformMatrix);
|
||||
descriptorSet->updateBuffer("vertexBuffer", 0, data.vertexBuffer);
|
||||
descriptorSet->updateBuffer("normalBuffer", 0, data.normalBuffer);
|
||||
descriptorSet->updateBuffer("indexBuffer", 0, data.indexBuffer);
|
||||
@@ -75,6 +84,7 @@ void FluidRenderPass::endFrame() {}
|
||||
void FluidRenderPass::publishOutputs() {
|
||||
}
|
||||
|
||||
|
||||
void FluidRenderPass::createRenderPass() {
|
||||
colorAttachment = resources->requestRenderTarget("BASEPASS_COLOR");
|
||||
colorAttachment.setLoadOp(Gfx::SE_ATTACHMENT_LOAD_OP_LOAD);
|
||||
@@ -112,6 +122,7 @@ void FluidRenderPass::createRenderPass() {
|
||||
Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
},
|
||||
};
|
||||
|
||||
renderPass = graphics->createRenderPass(layout, dependency, viewport->getRenderArea(), "FluidRenderPass");
|
||||
pipeline = graphics->createGraphicsPipeline(Gfx::LegacyPipelineCreateInfo{
|
||||
.vertexShader = vertexShader,
|
||||
@@ -124,7 +135,7 @@ void FluidRenderPass::createRenderPass() {
|
||||
},
|
||||
.rasterizationState =
|
||||
{
|
||||
.cullMode = Gfx::SE_CULL_MODE_FRONT_BIT,
|
||||
.cullMode = Gfx::SE_CULL_MODE_NONE,
|
||||
},
|
||||
.colorBlend =
|
||||
{
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "Math/Vector.h"
|
||||
#include "RenderGraph.h"
|
||||
#include "Scene/Scene.h"
|
||||
#include "Scene/LightEnvironment.h"
|
||||
|
||||
using namespace Seele;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "Graphics/StaticMeshVertexData.h"
|
||||
#include "Material/Material.h"
|
||||
#include "Material/MaterialInstance.h"
|
||||
#include "Scene/LightEnvironment.h"
|
||||
#include "RenderPass.h"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Graphics/Initializer.h"
|
||||
#include "Graphics/Shader.h"
|
||||
#include "Math/Matrix.h"
|
||||
#include "Scene/LightEnvironment.h"
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
#include <glm/matrix.hpp>
|
||||
|
||||
|
||||
@@ -7,13 +7,18 @@
|
||||
#include "Graphics/Initializer.h"
|
||||
#include "Graphics/Shader.h"
|
||||
#include "Math/Vector.h"
|
||||
#include <iostream>
|
||||
#include "Scene/FluidScene.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace Seele;
|
||||
|
||||
constexpr static int reinitInterval = 5;
|
||||
constexpr static int reinitIterations = 5;
|
||||
constexpr static float reinitDtau = 0.5f;
|
||||
// Reinitialization is in pseudo-time; keep it gentle to avoid eroding the interface each frame.
|
||||
constexpr static int reinitInterval = 20;
|
||||
constexpr static int reinitIterations = 1;
|
||||
constexpr static float reinitDtau = 0.05f;
|
||||
constexpr static int velocityDiffuseIterations = 8;
|
||||
constexpr static int pressureSolveIterations = 24;
|
||||
constexpr static int densityDiffuseIterations = 8;
|
||||
|
||||
#define SWAP(a, b) \
|
||||
{ \
|
||||
@@ -23,6 +28,12 @@ constexpr static float reinitDtau = 0.5f;
|
||||
}
|
||||
|
||||
SimulationComputePass::SimulationComputePass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graphics), scene(scene) {
|
||||
gridSizeLayout = graphics->createDescriptorLayout("gridParams");
|
||||
gridSizeLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||
.name = "gridSize",
|
||||
.uniformLength = sizeof(UVector),
|
||||
});
|
||||
gridSizeLayout->create();
|
||||
{
|
||||
setBounds.pipelineLayout = graphics->createPipelineLayout("SetBoundsPipelineLayout");
|
||||
setBounds.descriptorLayout = graphics->createDescriptorLayout("params");
|
||||
@@ -36,6 +47,7 @@ SimulationComputePass::SimulationComputePass(Gfx::PGraphics graphics, PScene sce
|
||||
});
|
||||
setBounds.descriptorLayout->create();
|
||||
setBounds.pipelineLayout->addDescriptorLayout(setBounds.descriptorLayout);
|
||||
setBounds.pipelineLayout->addDescriptorLayout(gridSizeLayout);
|
||||
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
||||
.name = "SetBound",
|
||||
.modules = {"SetBound"},
|
||||
@@ -84,6 +96,7 @@ SimulationComputePass::SimulationComputePass(Gfx::PGraphics graphics, PScene sce
|
||||
});
|
||||
linearSolve.descriptorLayout->create();
|
||||
linearSolve.pipelineLayout->addDescriptorLayout(linearSolve.descriptorLayout);
|
||||
linearSolve.pipelineLayout->addDescriptorLayout(gridSizeLayout);
|
||||
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
||||
.name = "LinearSolve",
|
||||
.modules = {"LinearSolve"},
|
||||
@@ -122,6 +135,7 @@ SimulationComputePass::SimulationComputePass(Gfx::PGraphics graphics, PScene sce
|
||||
});
|
||||
computeDivergence.descriptorLayout->create();
|
||||
computeDivergence.pipelineLayout->addDescriptorLayout(computeDivergence.descriptorLayout);
|
||||
computeDivergence.pipelineLayout->addDescriptorLayout(gridSizeLayout);
|
||||
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
||||
.name = "Divergence",
|
||||
.modules = {"Divergence"},
|
||||
@@ -157,6 +171,7 @@ SimulationComputePass::SimulationComputePass(Gfx::PGraphics graphics, PScene sce
|
||||
});
|
||||
project.descriptorLayout->create();
|
||||
project.pipelineLayout->addDescriptorLayout(project.descriptorLayout);
|
||||
project.pipelineLayout->addDescriptorLayout(gridSizeLayout);
|
||||
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
||||
.name = "Project",
|
||||
.modules = {"Project"},
|
||||
@@ -199,6 +214,7 @@ SimulationComputePass::SimulationComputePass(Gfx::PGraphics graphics, PScene sce
|
||||
});
|
||||
advect.descriptorLayout->create();
|
||||
advect.pipelineLayout->addDescriptorLayout(advect.descriptorLayout);
|
||||
advect.pipelineLayout->addDescriptorLayout(gridSizeLayout);
|
||||
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
||||
.name = "Advect",
|
||||
.modules = {"Advect"},
|
||||
@@ -230,7 +246,7 @@ SimulationComputePass::SimulationComputePass(Gfx::PGraphics graphics, PScene sce
|
||||
});
|
||||
reinitialize.descriptorLayout->create();
|
||||
reinitialize.pipelineLayout->addDescriptorLayout(reinitialize.descriptorLayout);
|
||||
|
||||
reinitialize.pipelineLayout->addDescriptorLayout(gridSizeLayout);
|
||||
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
||||
.name = "SignedDistance",
|
||||
.modules = {"SignedDistance"},
|
||||
@@ -244,6 +260,45 @@ SimulationComputePass::SimulationComputePass(Gfx::PGraphics graphics, PScene sce
|
||||
.pipelineLayout = reinitialize.pipelineLayout,
|
||||
});
|
||||
}
|
||||
{
|
||||
applyForces.pipelineLayout = graphics->createPipelineLayout("ApplyForcesPipelineLayout");
|
||||
applyForces.descriptorLayout = graphics->createDescriptorLayout("params");
|
||||
applyForces.descriptorLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||
.name = "velocityX",
|
||||
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
});
|
||||
applyForces.descriptorLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||
.name = "velocityY",
|
||||
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
});
|
||||
applyForces.descriptorLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||
.name = "velocityZ",
|
||||
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
});
|
||||
applyForces.descriptorLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||
.name = "force",
|
||||
.uniformLength = sizeof(Vector),
|
||||
});
|
||||
applyForces.descriptorLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||
.name = "dt",
|
||||
.uniformLength = sizeof(float),
|
||||
});
|
||||
applyForces.descriptorLayout->create();
|
||||
applyForces.pipelineLayout->addDescriptorLayout(applyForces.descriptorLayout);
|
||||
applyForces.pipelineLayout->addDescriptorLayout(gridSizeLayout);
|
||||
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
||||
.name = "ApplyForces",
|
||||
.modules = {"ApplyForces"},
|
||||
.entryPoints = {{"applyForces", "ApplyForces"}},
|
||||
.rootSignature = applyForces.pipelineLayout,
|
||||
});
|
||||
applyForces.pipelineLayout->create();
|
||||
applyForces.shader = graphics->createComputeShader({0});
|
||||
applyForces.pipeline = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
||||
.computeShader = applyForces.shader,
|
||||
.pipelineLayout = applyForces.pipelineLayout,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
SimulationComputePass::~SimulationComputePass() {}
|
||||
@@ -255,13 +310,21 @@ void SimulationComputePass::beginFrame(const Seele::Component::Camera&, const Se
|
||||
project.descriptorLayout->reset();
|
||||
advect.descriptorLayout->reset();
|
||||
reinitialize.descriptorLayout->reset();
|
||||
applyForces.descriptorLayout->reset();
|
||||
gridSizeLayout->reset();
|
||||
}
|
||||
|
||||
void SimulationComputePass::render() {
|
||||
for (auto& [entityID, data] : scene->getFluidScene()->getFluidDataMap()) {
|
||||
if (data.paused) {
|
||||
continue;
|
||||
}
|
||||
gridSizeSet = gridSizeLayout->allocateDescriptorSet();
|
||||
gridSizeSet->updateConstants("gridSize", 0, &data.gridSize);
|
||||
gridSizeSet->writeChanges();
|
||||
graphics->beginDebugRegion("Diffuse");
|
||||
for (uint iteration = 0; iteration < 4; ++iteration) {
|
||||
float a = dt * data.viscosity * (data.gridSize.x - 2) * (data.gridSize.y - 2) * (data.gridSize.z - 2);
|
||||
for (int iteration = 0; iteration < velocityDiffuseIterations; ++iteration) {
|
||||
float a = data.dt * data.viscosity * (data.gridSize.x - 2) * (data.gridSize.x - 2);
|
||||
float c = 1 + 6 * a;
|
||||
linearSolvePass(data.velocityXNextBuffer, data.velocityXBuffer, data.velocityX0Buffer, a, c, data.gridSize);
|
||||
linearSolvePass(data.velocityYNextBuffer, data.velocityYBuffer, data.velocityY0Buffer, a, c, data.gridSize);
|
||||
@@ -287,7 +350,7 @@ void SimulationComputePass::render() {
|
||||
Gfx::PShaderBuffer pressureNext = data.velocityZBuffer;
|
||||
divergencePass(divergence, pressureCurrent, data.velocityX0Buffer, data.velocityY0Buffer, data.velocityZ0Buffer, data.gridSize);
|
||||
|
||||
for (int iteration = 0; iteration < 4; ++iteration) {
|
||||
for (int iteration = 0; iteration < pressureSolveIterations; ++iteration) {
|
||||
linearSolvePass(pressureNext, pressureCurrent, divergence, 1, 6, data.gridSize);
|
||||
|
||||
setBoundsPass(pressureNext, 0, data.gridSize);
|
||||
@@ -304,15 +367,38 @@ void SimulationComputePass::render() {
|
||||
graphics->endDebugRegion();
|
||||
|
||||
graphics->beginDebugRegion("Advect");
|
||||
advectPass(data.velocityXBuffer, data.velocityX0Buffer, data.velocityX0Buffer, data.velocityY0Buffer, data.velocityZ0Buffer, dt, data.gridSize);
|
||||
advectPass(data.velocityYBuffer, data.velocityY0Buffer, data.velocityX0Buffer, data.velocityY0Buffer, data.velocityZ0Buffer, dt, data.gridSize);
|
||||
advectPass(data.velocityZBuffer, data.velocityZ0Buffer, data.velocityX0Buffer, data.velocityY0Buffer, data.velocityZ0Buffer, dt, data.gridSize);
|
||||
advectPass(data.velocityXBuffer, data.velocityX0Buffer, data.velocityX0Buffer, data.velocityY0Buffer, data.velocityZ0Buffer, data.dt,
|
||||
data.gridSize);
|
||||
advectPass(data.velocityYBuffer, data.velocityY0Buffer, data.velocityX0Buffer, data.velocityY0Buffer, data.velocityZ0Buffer, data.dt,
|
||||
data.gridSize);
|
||||
advectPass(data.velocityZBuffer, data.velocityZ0Buffer, data.velocityX0Buffer, data.velocityY0Buffer, data.velocityZ0Buffer, data.dt,
|
||||
data.gridSize);
|
||||
|
||||
if (data.enableGravity) {
|
||||
applyForcesPass(data.velocityXBuffer, data.velocityYBuffer, data.velocityZBuffer, data.gravity, data.dt, data.gridSize);
|
||||
}
|
||||
|
||||
// Set boundary conditions after advection/forces so the divergence sees correct wall values
|
||||
setBoundsPass(data.velocityXBuffer, 1, data.gridSize);
|
||||
setBoundsPass(data.velocityYBuffer, 2, data.gridSize);
|
||||
setBoundsPass(data.velocityZBuffer, 3, data.gridSize);
|
||||
|
||||
// Re-project after advection/forces to keep the final velocity field divergence-free.
|
||||
Gfx::PShaderBuffer advectedDivergence = data.velocityXNextBuffer;
|
||||
Gfx::PShaderBuffer advectedPressureCurrent = data.velocityYNextBuffer;
|
||||
Gfx::PShaderBuffer advectedPressureNext = data.velocityZNextBuffer;
|
||||
divergencePass(advectedDivergence, advectedPressureCurrent, data.velocityXBuffer, data.velocityYBuffer, data.velocityZBuffer, data.gridSize);
|
||||
for (int iteration = 0; iteration < pressureSolveIterations; ++iteration) {
|
||||
linearSolvePass(advectedPressureNext, advectedPressureCurrent, advectedDivergence, 1, 6, data.gridSize);
|
||||
setBoundsPass(advectedPressureNext, 0, data.gridSize);
|
||||
SWAP(advectedPressureCurrent, advectedPressureNext);
|
||||
}
|
||||
projectPass(data.velocityXBuffer, data.velocityYBuffer, data.velocityZBuffer, advectedPressureCurrent, data.gridSize);
|
||||
|
||||
setBoundsPass(data.velocityXBuffer, 1, data.gridSize);
|
||||
setBoundsPass(data.velocityYBuffer, 2, data.gridSize);
|
||||
setBoundsPass(data.velocityZBuffer, 3, data.gridSize);
|
||||
graphics->endDebugRegion();
|
||||
|
||||
// swap velocity buffers
|
||||
SWAP(data.velocityX0Buffer, data.velocityXBuffer);
|
||||
SWAP(data.velocityY0Buffer, data.velocityYBuffer);
|
||||
@@ -326,8 +412,8 @@ void SimulationComputePass::render() {
|
||||
graphics->copyBuffer(density0, densityCurrent);
|
||||
densityCurrent->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
for (int iteration = 0; iteration < 4; ++iteration) {
|
||||
float a = dt * data.diffusion * (data.gridSize.x - 2) * (data.gridSize.y - 2) * (data.gridSize.z - 2);
|
||||
for (int iteration = 0; iteration < densityDiffuseIterations; ++iteration) {
|
||||
float a = data.dt * data.diffusion * (data.gridSize.x - 2) * (data.gridSize.x - 2);
|
||||
float c = 1 + 6 * a;
|
||||
linearSolvePass(densityNext, densityCurrent, density0, a, c, data.gridSize);
|
||||
setBoundsPass(densityNext, 0, data.gridSize);
|
||||
@@ -335,12 +421,13 @@ void SimulationComputePass::render() {
|
||||
}
|
||||
graphics->endDebugRegion();
|
||||
graphics->beginDebugRegion("AdvectDensity");
|
||||
advectPass(data.density0Buffer, densityCurrent, data.velocityX0Buffer, data.velocityY0Buffer, data.velocityZ0Buffer, dt, data.gridSize);
|
||||
advectPass(data.density0Buffer, densityCurrent, data.velocityX0Buffer, data.velocityY0Buffer, data.velocityZ0Buffer, data.dt,
|
||||
data.gridSize);
|
||||
setBoundsPass(data.density0Buffer, 0, data.gridSize);
|
||||
graphics->endDebugRegion();
|
||||
|
||||
graphics->beginDebugRegion("AdvectLevelSet");
|
||||
advectPass(data.phiBuffer, data.phi0Buffer, data.velocityX0Buffer, data.velocityY0Buffer, data.velocityZ0Buffer, dt, data.gridSize);
|
||||
advectPass(data.phiBuffer, data.phi0Buffer, data.velocityX0Buffer, data.velocityY0Buffer, data.velocityZ0Buffer, data.dt, data.gridSize);
|
||||
setBoundsPass(data.phiBuffer, 0, data.gridSize);
|
||||
|
||||
// Reinitialize level set every N frames to restore |grad phi| = 1
|
||||
@@ -380,7 +467,11 @@ void SimulationComputePass::setBoundsPass(Gfx::PShaderBuffer grid, int b, UVecto
|
||||
Gfx::OComputeCommand boundsCommand = graphics->createComputeCommand();
|
||||
boundsCommand->bindPipeline(setBounds.pipeline);
|
||||
boundsCommand->bindDescriptor(bounds);
|
||||
boundsCommand->dispatch(getDispatchSize(gridSize, setBounds.threadGroupSize));
|
||||
boundsCommand->bindDescriptor(gridSizeSet);
|
||||
// Dispatch covers max(gridSize.x, gridSize.y) x max(gridSize.y, gridSize.z) to handle all faces on non-cubic grids
|
||||
UVector faceDispatchGrid = {std::max(gridSize.x, gridSize.y), std::max(gridSize.y, gridSize.z), 1};
|
||||
auto dispatchSize = getDispatchSize(faceDispatchGrid, setBounds.threadGroupSize);
|
||||
boundsCommand->dispatch(dispatchSize.x, dispatchSize.y, 1);
|
||||
graphics->executeCommands(std::move(boundsCommand));
|
||||
|
||||
grid->pipelineBarrier(Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, Gfx::SE_ACCESS_SHADER_WRITE_BIT,
|
||||
@@ -389,7 +480,10 @@ void SimulationComputePass::setBoundsPass(Gfx::PShaderBuffer grid, int b, UVecto
|
||||
Gfx::OComputeCommand edgesCommand = graphics->createComputeCommand();
|
||||
edgesCommand->bindPipeline(setBounds.pipelineEdges);
|
||||
edgesCommand->bindDescriptor(bounds);
|
||||
edgesCommand->dispatch(getDispatchSize(gridSize, setBounds.threadGroupSize).x, 1, 1);
|
||||
edgesCommand->bindDescriptor(gridSizeSet);
|
||||
// Dispatch covers max dimension to handle all 12 edges on non-cubic grids; edge shader uses numthreads(128,1,1)
|
||||
uint32_t maxDim = std::max({gridSize.x, gridSize.y, gridSize.z});
|
||||
edgesCommand->dispatch((maxDim + 127) / 128, 1, 1);
|
||||
graphics->executeCommands(std::move(edgesCommand));
|
||||
|
||||
grid->pipelineBarrier(Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, Gfx::SE_ACCESS_SHADER_WRITE_BIT,
|
||||
@@ -398,6 +492,7 @@ void SimulationComputePass::setBoundsPass(Gfx::PShaderBuffer grid, int b, UVecto
|
||||
Gfx::OComputeCommand cornersCommand = graphics->createComputeCommand();
|
||||
cornersCommand->bindPipeline(setBounds.pipelineCorners);
|
||||
cornersCommand->bindDescriptor(bounds);
|
||||
cornersCommand->bindDescriptor(gridSizeSet);
|
||||
cornersCommand->dispatch(1, 1, 1);
|
||||
graphics->executeCommands(std::move(cornersCommand));
|
||||
|
||||
@@ -405,7 +500,8 @@ void SimulationComputePass::setBoundsPass(Gfx::PShaderBuffer grid, int b, UVecto
|
||||
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
|
||||
void SimulationComputePass::linearSolvePass(Gfx::PShaderBuffer next, Gfx::PShaderBuffer current, Gfx::PShaderBuffer grid0, float a, float c, UVector gridSize) {
|
||||
void SimulationComputePass::linearSolvePass(Gfx::PShaderBuffer next, Gfx::PShaderBuffer current, Gfx::PShaderBuffer grid0, float a, float c,
|
||||
UVector gridSize) {
|
||||
Gfx::ODescriptorSet solve = linearSolve.descriptorLayout->allocateDescriptorSet();
|
||||
solve->updateBuffer("next", 0, next);
|
||||
solve->updateBuffer("current", 0, current);
|
||||
@@ -416,6 +512,7 @@ void SimulationComputePass::linearSolvePass(Gfx::PShaderBuffer next, Gfx::PShade
|
||||
Gfx::OComputeCommand solveCommand = graphics->createComputeCommand();
|
||||
solveCommand->bindPipeline(linearSolve.pipeline);
|
||||
solveCommand->bindDescriptor(solve);
|
||||
solveCommand->bindDescriptor(gridSizeSet);
|
||||
solveCommand->dispatch(getDispatchSize(gridSize, linearSolve.threadGroupSize));
|
||||
graphics->executeCommands(std::move(solveCommand));
|
||||
|
||||
@@ -435,6 +532,7 @@ void SimulationComputePass::divergencePass(Seele::Gfx::PShaderBuffer divergence,
|
||||
Gfx::OComputeCommand divergenceCommand = graphics->createComputeCommand();
|
||||
divergenceCommand->bindPipeline(computeDivergence.pipeline);
|
||||
divergenceCommand->bindDescriptor(divergenceSet);
|
||||
divergenceCommand->bindDescriptor(gridSizeSet);
|
||||
divergenceCommand->dispatch(getDispatchSize(gridSize, computeDivergence.threadGroupSize));
|
||||
graphics->executeCommands(std::move(divergenceCommand));
|
||||
// divergence is now in velocityXBuffer, pressure is in velocityYBuffer
|
||||
@@ -455,6 +553,7 @@ void SimulationComputePass::projectPass(Seele::Gfx::PShaderBuffer velocityX, See
|
||||
Gfx::OComputeCommand projectCommand = graphics->createComputeCommand();
|
||||
projectCommand->bindPipeline(project.pipeline);
|
||||
projectCommand->bindDescriptor(projectSet);
|
||||
projectCommand->bindDescriptor(gridSizeSet);
|
||||
projectCommand->dispatch(getDispatchSize(gridSize, project.threadGroupSize));
|
||||
graphics->executeCommands(std::move(projectCommand));
|
||||
|
||||
@@ -479,6 +578,7 @@ void SimulationComputePass::advectPass(Gfx::PShaderBuffer quantity, Gfx::PShader
|
||||
Gfx::OComputeCommand advectCommand = graphics->createComputeCommand();
|
||||
advectCommand->bindPipeline(advect.pipeline);
|
||||
advectCommand->bindDescriptor(advectSet);
|
||||
advectCommand->bindDescriptor(gridSizeSet);
|
||||
advectCommand->dispatch(getDispatchSize(gridSize, advect.threadGroupSize));
|
||||
graphics->executeCommands(std::move(advectCommand));
|
||||
|
||||
@@ -486,6 +586,29 @@ void SimulationComputePass::advectPass(Gfx::PShaderBuffer quantity, Gfx::PShader
|
||||
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
|
||||
void SimulationComputePass::applyForcesPass(Gfx::PShaderBuffer velocityX, Gfx::PShaderBuffer velocityY, Gfx::PShaderBuffer velocityZ, Vector gravity, float dt, UVector gridSize) {
|
||||
Gfx::ODescriptorSet forcesSet = applyForces.descriptorLayout->allocateDescriptorSet();
|
||||
forcesSet->updateBuffer("velocityX", 0, velocityX);
|
||||
forcesSet->updateBuffer("velocityY", 0, velocityY);
|
||||
forcesSet->updateBuffer("velocityZ", 0, velocityZ);
|
||||
forcesSet->updateConstants("force", 0, &gravity);
|
||||
forcesSet->updateConstants("dt", 0, &dt);
|
||||
forcesSet->writeChanges();
|
||||
Gfx::OComputeCommand forcesCommand = graphics->createComputeCommand();
|
||||
forcesCommand->bindPipeline(applyForces.pipeline);
|
||||
forcesCommand->bindDescriptor(forcesSet);
|
||||
forcesCommand->bindDescriptor(gridSizeSet);
|
||||
forcesCommand->dispatch(getDispatchSize(gridSize, applyForces.threadGroupSize));
|
||||
graphics->executeCommands(std::move(forcesCommand));
|
||||
|
||||
velocityX->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, Gfx::SE_ACCESS_SHADER_READ_BIT,
|
||||
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
velocityY->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, Gfx::SE_ACCESS_SHADER_READ_BIT,
|
||||
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
velocityZ->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, Gfx::SE_ACCESS_SHADER_READ_BIT,
|
||||
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
|
||||
void SimulationComputePass::reinitializeLevelSetPass(Seele::Gfx::PShaderBuffer phi, Seele::Gfx::PShaderBuffer phi0, UVector gridSize) {
|
||||
graphics->beginDebugRegion("ReinitializeLevelSet");
|
||||
// Snapshot current phi into phi0 for the sign function
|
||||
@@ -507,6 +630,7 @@ void SimulationComputePass::reinitializeLevelSetPass(Seele::Gfx::PShaderBuffer p
|
||||
Gfx::OComputeCommand reinitCommand = graphics->createComputeCommand();
|
||||
reinitCommand->bindPipeline(reinitialize.pipeline);
|
||||
reinitCommand->bindDescriptor(reinitSet);
|
||||
reinitCommand->bindDescriptor(gridSizeSet);
|
||||
reinitCommand->dispatch(getDispatchSize(gridSize, reinitialize.threadGroupSize));
|
||||
graphics->executeCommands(std::move(reinitCommand));
|
||||
|
||||
|
||||
@@ -75,8 +75,17 @@ class SimulationComputePass : public RenderPass {
|
||||
Gfx::PComputePipeline pipeline;
|
||||
constexpr static UVector threadGroupSize = {32, 8, 1};
|
||||
} reinitialize;
|
||||
struct ApplyForces {
|
||||
Gfx::OPipelineLayout pipelineLayout;
|
||||
Gfx::ODescriptorLayout descriptorLayout;
|
||||
Gfx::OComputeShader shader;
|
||||
Gfx::PComputePipeline pipeline;
|
||||
constexpr static UVector threadGroupSize = {32, 8, 1};
|
||||
} applyForces;
|
||||
void applyForcesPass(Gfx::PShaderBuffer velocityX, Gfx::PShaderBuffer velocityY, Gfx::PShaderBuffer velocityZ, Vector gravity, float dt, UVector gridSize);
|
||||
Gfx::ODescriptorLayout gridSizeLayout;
|
||||
Gfx::ODescriptorSet gridSizeSet;
|
||||
PScene scene;
|
||||
constexpr static float dt = 0.1f;
|
||||
};
|
||||
DEFINE_REF(SimulationComputePass)
|
||||
} // namespace Seele
|
||||
@@ -5,21 +5,18 @@
|
||||
#include "Graphics/Graphics.h"
|
||||
#include "Graphics/Initializer.h"
|
||||
#include "Graphics/Shader.h"
|
||||
#include "Math/Vector.h"
|
||||
#include "Scene/FluidScene.h"
|
||||
|
||||
using namespace Seele;
|
||||
|
||||
// Linearly interpolate the position where the isosurface crosses the edge
|
||||
// between two grid points.
|
||||
static Vector vertexInterp(float isolevel, const Vector& p1, const Vector& p2, float v1, float v2) {
|
||||
if (std::abs(v1 - v2) < 1e-10f)
|
||||
return p1;
|
||||
float t = (isolevel - v1) / (v2 - v1);
|
||||
return Vector(p1.x + t * (p2.x - p1.x), p1.y + t * (p2.y - p1.y), p1.z + t * (p2.z - p1.z));
|
||||
}
|
||||
|
||||
SurfaceExtractPass::SurfaceExtractPass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graphics), scene(scene) {
|
||||
pipelineLayout = graphics->createPipelineLayout("SurfaceExtractPipelineLayout");
|
||||
gridSizeLayout = graphics->createDescriptorLayout("gridParams");
|
||||
gridSizeLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||
.name = "gridSize",
|
||||
.uniformLength = sizeof(UVector),
|
||||
});
|
||||
gridSizeLayout->create();
|
||||
descriptorLayout = graphics->createDescriptorLayout("params");
|
||||
descriptorLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||
.name = "vertexBuffer",
|
||||
@@ -43,6 +40,7 @@ SurfaceExtractPass::SurfaceExtractPass(Gfx::PGraphics graphics, PScene scene) :
|
||||
});
|
||||
descriptorLayout->create();
|
||||
pipelineLayout->addDescriptorLayout(descriptorLayout);
|
||||
pipelineLayout->addDescriptorLayout(gridSizeLayout);
|
||||
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
||||
.name = "MarchingCubes",
|
||||
.modules = {"MarchingCubes"},
|
||||
@@ -62,8 +60,12 @@ SurfaceExtractPass::~SurfaceExtractPass() {}
|
||||
|
||||
void SurfaceExtractPass::beginFrame(const Seele::Component::Camera&, const Seele::Component::Transform&) {}
|
||||
|
||||
|
||||
void SurfaceExtractPass::render() {
|
||||
for (auto& [entityID, data] : scene->getFluidScene()->getFluidDataMap()) {
|
||||
Gfx::ODescriptorSet gridSizeSet = gridSizeLayout->allocateDescriptorSet();
|
||||
gridSizeSet->updateConstants("gridSize", 0, &data.gridSize);
|
||||
gridSizeSet->writeChanges();
|
||||
data.vertexBuffer->rotateBuffer(data.getVertexBufferSize() * sizeof(float));
|
||||
data.normalBuffer->rotateBuffer(data.getVertexBufferSize() * sizeof(float));
|
||||
data.indexBuffer->rotateBuffer(data.getIndexBufferSize() * sizeof(uint32));
|
||||
@@ -83,6 +85,7 @@ void SurfaceExtractPass::render() {
|
||||
Gfx::OComputeCommand cmd = graphics->createComputeCommand();
|
||||
cmd->bindPipeline(pipeline);
|
||||
cmd->bindDescriptor(descriptorSet);
|
||||
cmd->bindDescriptor(gridSizeSet);
|
||||
cmd->dispatch((data.gridSize + threadGroupSize - 1u) / threadGroupSize);
|
||||
graphics->executeCommands(std::move(cmd));
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ private:
|
||||
|
||||
Gfx::OPipelineLayout pipelineLayout;
|
||||
Gfx::ODescriptorLayout descriptorLayout;
|
||||
Gfx::ODescriptorLayout gridSizeLayout;
|
||||
Gfx::ODescriptorSet descriptorSet;
|
||||
Gfx::OComputeShader computeShader;
|
||||
Gfx::PComputePipeline pipeline;
|
||||
|
||||
@@ -848,6 +848,7 @@ void Graphics::pickPhysicalDevice() {
|
||||
|
||||
vkGetPhysicalDeviceProperties2(physicalDevice, &props.get());
|
||||
features.get<VkPhysicalDeviceFeatures2>().features = {
|
||||
// .robustBufferAccess = true,
|
||||
.geometryShader = true,
|
||||
.sampleRateShading = true,
|
||||
.fillModeNonSolid = true,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "slang-compile.h"
|
||||
#include "Containers/Array.h"
|
||||
#include "Graphics/Descriptor.h"
|
||||
#include <array>
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <fmt/core.h>
|
||||
#include <iostream>
|
||||
@@ -29,113 +31,54 @@ thread_local Slang::ComPtr<slang::ISession> session;
|
||||
thread_local Array<std::string> entryPoints;
|
||||
|
||||
namespace {
|
||||
std::filesystem::path getExecutableDirectory() {
|
||||
std::error_code error;
|
||||
auto exePath = std::filesystem::read_symlink("/proc/self/exe", error);
|
||||
if (!error) {
|
||||
return exePath.parent_path();
|
||||
void appendEnvPath(const char* varName, const std::filesystem::path& path) {
|
||||
if (!std::filesystem::exists(path) || !std::filesystem::is_directory(path)) {
|
||||
return;
|
||||
}
|
||||
return std::filesystem::current_path();
|
||||
|
||||
const std::string newEntry = path.lexically_normal().string();
|
||||
const char* currentRaw = std::getenv(varName);
|
||||
std::string current = currentRaw ? currentRaw : "";
|
||||
if (current.find(newEntry) != std::string::npos) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string updated = current.empty() ? newEntry : (newEntry + ":" + current);
|
||||
setenv(varName, updated.c_str(), 1);
|
||||
}
|
||||
|
||||
std::filesystem::path findExistingDirectory(std::initializer_list<std::filesystem::path> candidates) {
|
||||
void configureSlangRuntimeEnv() {
|
||||
std::filesystem::path exePath;
|
||||
try {
|
||||
exePath = std::filesystem::canonical("/proc/self/exe");
|
||||
} catch (...) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::filesystem::path exeDir = exePath.parent_path();
|
||||
const std::array<std::filesystem::path, 7> candidates = {
|
||||
exeDir / "vcpkg_installed/x64-linux/lib",
|
||||
exeDir / "vcpkg_installed/x64-linux/debug/lib",
|
||||
exeDir / "vcpkg_installed/x64-linux/tools/shader-slang",
|
||||
exeDir.parent_path() / "vcpkg_installed/x64-linux/lib",
|
||||
exeDir.parent_path() / "vcpkg_installed/x64-linux/debug/lib",
|
||||
exeDir.parent_path() / "vcpkg_installed/x64-linux/tools/shader-slang",
|
||||
std::filesystem::current_path() / "build/vcpkg_installed/x64-linux/tools/shader-slang",
|
||||
};
|
||||
|
||||
for (const auto& candidate : candidates) {
|
||||
std::error_code error;
|
||||
if (std::filesystem::exists(candidate, error) && std::filesystem::is_directory(candidate, error)) {
|
||||
return candidate;
|
||||
appendEnvPath("LD_LIBRARY_PATH", candidate);
|
||||
appendEnvPath("PATH", candidate);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool containsDownstreamCompilerArtifacts(const std::filesystem::path& directory) {
|
||||
std::error_code error;
|
||||
if (!std::filesystem::exists(directory, error) || !std::filesystem::is_directory(directory, error)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(directory, error)) {
|
||||
if (error || !entry.is_regular_file(error)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto fileName = entry.path().filename().string();
|
||||
if (fileName.rfind("slang-glslang", 0) == 0 || fileName.rfind("spirv-opt", 0) == 0 || fileName.rfind("spirv-dis", 0) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasArtifactWithPrefix(const std::filesystem::path& directory, const char* prefix) {
|
||||
std::error_code error;
|
||||
if (!std::filesystem::exists(directory, error) || !std::filesystem::is_directory(directory, error)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(directory, error)) {
|
||||
if (error || !entry.is_regular_file(error)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.path().filename().string().rfind(prefix, 0) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::filesystem::path findDownstreamCompilerDirectory(std::initializer_list<std::filesystem::path> candidates) {
|
||||
for (const auto& candidate : candidates) {
|
||||
if (containsDownstreamCompilerArtifacts(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return findExistingDirectory(candidates);
|
||||
}
|
||||
|
||||
void configureDownstreamCompilers(slang::IGlobalSession* session) {
|
||||
const auto executableDirectory = getExecutableDirectory();
|
||||
const auto currentDirectory = std::filesystem::current_path();
|
||||
const auto glslangDirectory = findDownstreamCompilerDirectory({
|
||||
executableDirectory,
|
||||
executableDirectory / "Seele",
|
||||
executableDirectory / "vcpkg_installed" / "x64-linux" / "lib",
|
||||
currentDirectory / "build",
|
||||
currentDirectory / "build" / "Seele",
|
||||
currentDirectory / "Seele",
|
||||
currentDirectory / "vcpkg_installed" / "x64-linux" / "lib",
|
||||
});
|
||||
|
||||
if (!glslangDirectory.empty()) {
|
||||
const std::string path = glslangDirectory.string();
|
||||
if (hasArtifactWithPrefix(glslangDirectory, "slang-glslang") || hasArtifactWithPrefix(glslangDirectory, "libslang-glslang")) {
|
||||
session->setDownstreamCompilerPath(SLANG_PASS_THROUGH_GLSLANG, path.c_str());
|
||||
}
|
||||
if (hasArtifactWithPrefix(glslangDirectory, "spirv-opt")) {
|
||||
session->setDownstreamCompilerPath(SLANG_PASS_THROUGH_SPIRV_OPT, path.c_str());
|
||||
}
|
||||
if (hasArtifactWithPrefix(glslangDirectory, "spirv-dis")) {
|
||||
session->setDownstreamCompilerPath(SLANG_PASS_THROUGH_SPIRV_DIS, path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid optional SPIR-V downstream tools that are often unavailable in RenderDoc launch environments.
|
||||
session->setDefaultDownstreamCompiler(SLANG_SOURCE_LANGUAGE_SPIRV, SLANG_PASS_THROUGH_NONE);
|
||||
session->setDownstreamCompilerForTransition(SLANG_SPIRV, SLANG_SPIRV, SLANG_PASS_THROUGH_NONE);
|
||||
session->setDownstreamCompilerForTransition(SLANG_SPIRV, SLANG_SPIRV_ASM, SLANG_PASS_THROUGH_NONE);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void Seele::beginCompilation(const ShaderCompilationInfo& info, SlangCompileTarget target, Gfx::PPipelineLayout layout) {
|
||||
if (!globalSession) {
|
||||
configureSlangRuntimeEnv();
|
||||
SlangGlobalSessionDesc sessionDesc = {};
|
||||
sessionDesc.enableGLSL = true;
|
||||
slang::createGlobalSession(&sessionDesc, globalSession.writeRef());
|
||||
configureDownstreamCompilers(globalSession);
|
||||
}
|
||||
slang::SessionDesc sessionDesc;
|
||||
sessionDesc.flags = 0;
|
||||
@@ -156,6 +99,22 @@ void Seele::beginCompilation(const ShaderCompilationInfo& info, SlangCompileTarg
|
||||
.intValue0 = SLANG_OPTIMIZATION_LEVEL_NONE,
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = slang::CompilerOptionName::EmitSpirvMethod,
|
||||
.value =
|
||||
{
|
||||
.kind = slang::CompilerOptionValueKind::Int,
|
||||
.intValue0 = SLANG_EMIT_SPIRV_DIRECTLY,
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = slang::CompilerOptionName::PassThrough,
|
||||
.value =
|
||||
{
|
||||
.kind = slang::CompilerOptionValueKind::Int,
|
||||
.intValue0 = SLANG_PASS_THROUGH_NONE,
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = slang::CompilerOptionName::SkipSPIRVValidation,
|
||||
.value =
|
||||
|
||||
+110
-38
@@ -1,9 +1,45 @@
|
||||
#include "FluidScene.h"
|
||||
#include "Graphics/Command.h"
|
||||
#include "Graphics/Descriptor.h"
|
||||
#include "Graphics/Enums.h"
|
||||
#include "Graphics/Initializer.h"
|
||||
|
||||
using namespace Seele;
|
||||
|
||||
FluidScene::FluidScene(Gfx::PGraphics graphics) : graphics(graphics) {}
|
||||
FluidScene::FluidScene(Gfx::PGraphics graphics) : graphics(graphics) {
|
||||
pipelineLayout = graphics->createPipelineLayout("FluidScenePipelineLayout");
|
||||
gridParamsLayout = graphics->createDescriptorLayout("gridParams");
|
||||
gridParamsLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||
.name = "gridSize",
|
||||
.uniformLength = sizeof(UVector),
|
||||
});
|
||||
gridParamsLayout->create();
|
||||
descriptorLayout = graphics->createDescriptorLayout("params");
|
||||
descriptorLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||
.name = "phi",
|
||||
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
});
|
||||
descriptorLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||
.name = "density",
|
||||
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
});
|
||||
descriptorLayout->create();
|
||||
pipelineLayout->addDescriptorLayout(descriptorLayout);
|
||||
pipelineLayout->addDescriptorLayout(gridParamsLayout);
|
||||
|
||||
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
||||
.name = "AddSource",
|
||||
.modules = {"AddSource"},
|
||||
.entryPoints = {{"addSource", "AddSource"}},
|
||||
.rootSignature = pipelineLayout,
|
||||
});
|
||||
pipelineLayout->create();
|
||||
shader = graphics->createComputeShader({0});
|
||||
pipeline = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
||||
.computeShader = shader,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
});
|
||||
}
|
||||
|
||||
FluidScene::~FluidScene() {}
|
||||
|
||||
@@ -12,37 +48,37 @@ void FluidScene::updateFluidData(uint32 entityID, const Component::Transform& tr
|
||||
auto& data = fluidDataMap[entityID];
|
||||
uint64 totalCells = (uint64)grid.gridSize.x * grid.gridSize.y * grid.gridSize.z;
|
||||
uint64 bufferSize = totalCells * sizeof(float);
|
||||
Array<float> initialDensity(bufferSize / sizeof(float));
|
||||
Array<float> initialVelocityX(bufferSize / sizeof(float));
|
||||
Array<float> initialVelocityY(bufferSize / sizeof(float));
|
||||
Array<float> initialVelocityZ(bufferSize / sizeof(float));
|
||||
Array<float> initialPhi(bufferSize / sizeof(float));
|
||||
// Array<float> initialDensity(bufferSize / sizeof(float));
|
||||
// Array<float> initialVelocityX(bufferSize / sizeof(float));
|
||||
// Array<float> initialVelocityY(bufferSize / sizeof(float));
|
||||
// Array<float> initialVelocityZ(bufferSize / sizeof(float));
|
||||
// Array<float> initialPhi(bufferSize / sizeof(float));
|
||||
|
||||
// Initialize level set to positive (outside) everywhere
|
||||
float halfGridX = static_cast<float>(grid.gridSize.x) * 0.5f;
|
||||
float halfGridY = static_cast<float>(grid.gridSize.y) * 0.5f;
|
||||
float radius = static_cast<float>(grid.gridSize.x) * 0.2f;
|
||||
// Place sphere center in the lower portion of the grid
|
||||
float cx = halfGridX;
|
||||
float cy = halfGridY;
|
||||
float cz = static_cast<float>(grid.gridSize.z) * 0.3f;
|
||||
for (uint32 z = 1; z < grid.gridSize.z - 1; ++z) {
|
||||
for (uint32 y = 1; y < grid.gridSize.y - 1; ++y) {
|
||||
for (uint32 x = 1; x < grid.gridSize.x - 1; ++x) {
|
||||
uint32 idx = x + grid.gridSize.x * y + grid.gridSize.x * grid.gridSize.y * z;
|
||||
float dx = static_cast<float>(x) - cx;
|
||||
float dy = static_cast<float>(y) - cy;
|
||||
float dz = static_cast<float>(z) - cz;
|
||||
float dist = std::sqrt(dx * dx + dy * dy + dz * dz);
|
||||
initialPhi[idx] = dist - radius;
|
||||
if (dist < radius) {
|
||||
initialDensity[idx] = 1.0f;
|
||||
// Give an initial upward velocity to kick the simulation
|
||||
initialVelocityZ[idx] = 5.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// // Initialize level set to positive (outside) everywhere
|
||||
// float halfGridX = static_cast<float>(grid.gridSize.x) * 0.5f;
|
||||
// float halfGridY = static_cast<float>(grid.gridSize.y) * 0.5f;
|
||||
// float radius = static_cast<float>(grid.gridSize.x) * 0.2f;
|
||||
// // Place sphere center in the lower portion of the grid
|
||||
// float cx = halfGridX;
|
||||
// float cy = halfGridY;
|
||||
// float cz = static_cast<float>(grid.gridSize.z) * 0.3f;
|
||||
// for (uint32 z = 1; z < grid.gridSize.z - 1; ++z) {
|
||||
// for (uint32 y = 1; y < grid.gridSize.y - 1; ++y) {
|
||||
// for (uint32 x = 1; x < grid.gridSize.x - 1; ++x) {
|
||||
// uint32 idx = x + grid.gridSize.x * y + grid.gridSize.x * grid.gridSize.y * z;
|
||||
// float dx = static_cast<float>(x) - cx;
|
||||
// float dy = static_cast<float>(y) - cy;
|
||||
// float dz = static_cast<float>(z) - cz;
|
||||
// float dist = std::sqrt(dx * dx + dy * dy + dz * dz);
|
||||
// initialPhi[idx] = dist - radius;
|
||||
// if (dist < radius) {
|
||||
// initialDensity[idx] = 1.0f;
|
||||
// // Give an initial upward velocity to kick the simulation
|
||||
// initialVelocityZ[idx] = 5.0f;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
data.phiBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
@@ -55,7 +91,7 @@ void FluidScene::updateFluidData(uint32 entityID, const Component::Transform& tr
|
||||
.sourceData =
|
||||
{
|
||||
.size = bufferSize,
|
||||
.data = (uint8*)initialPhi.data(),
|
||||
// .data = (uint8*)initialPhi.data(),
|
||||
},
|
||||
.name = "Phi0Buffer",
|
||||
});
|
||||
@@ -70,7 +106,7 @@ void FluidScene::updateFluidData(uint32 entityID, const Component::Transform& tr
|
||||
.sourceData =
|
||||
{
|
||||
.size = bufferSize,
|
||||
.data = (uint8*)initialDensity.data(),
|
||||
// .data = (uint8*)initialDensity.data(),
|
||||
},
|
||||
.name = "Density0Buffer",
|
||||
});
|
||||
@@ -127,7 +163,7 @@ void FluidScene::updateFluidData(uint32 entityID, const Component::Transform& tr
|
||||
.sourceData =
|
||||
{
|
||||
.size = bufferSize,
|
||||
.data = (uint8*)initialVelocityX.data(),
|
||||
// .data = (uint8*)initialVelocityX.data(),
|
||||
},
|
||||
.name = "VelocityX0Buffer",
|
||||
});
|
||||
@@ -135,7 +171,7 @@ void FluidScene::updateFluidData(uint32 entityID, const Component::Transform& tr
|
||||
.sourceData =
|
||||
{
|
||||
.size = bufferSize,
|
||||
.data = (uint8*)initialVelocityY.data(),
|
||||
// .data = (uint8*)initialVelocityY.data(),
|
||||
},
|
||||
.name = "VelocityY0Buffer",
|
||||
});
|
||||
@@ -143,7 +179,7 @@ void FluidScene::updateFluidData(uint32 entityID, const Component::Transform& tr
|
||||
.sourceData =
|
||||
{
|
||||
.size = bufferSize,
|
||||
.data = (uint8*)initialVelocityZ.data(),
|
||||
// .data = (uint8*)initialVelocityZ.data(),
|
||||
},
|
||||
.name = "VelocityZ0Buffer",
|
||||
});
|
||||
@@ -157,7 +193,8 @@ void FluidScene::updateFluidData(uint32 entityID, const Component::Transform& tr
|
||||
.name = "IndexBuffer",
|
||||
});
|
||||
data.surfaceCountBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData = {
|
||||
.sourceData =
|
||||
{
|
||||
.size = 4 * sizeof(uint32),
|
||||
},
|
||||
.usage = Gfx::SE_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
|
||||
@@ -165,9 +202,44 @@ void FluidScene::updateFluidData(uint32 entityID, const Component::Transform& tr
|
||||
});
|
||||
}
|
||||
auto& data = fluidDataMap[entityID];
|
||||
data.paused = grid.paused;
|
||||
data.transform = transform.transform;
|
||||
data.cellSize = grid.cellSize;
|
||||
data.dt = grid.dt;
|
||||
data.viscosity = grid.viscosity;
|
||||
data.diffusion = grid.diffusion;
|
||||
data.gridSize = grid.gridSize;
|
||||
data.gravity = grid.gravity;
|
||||
data.enableGravity = grid.enableGravity;
|
||||
}
|
||||
|
||||
void FluidScene::addSource() {
|
||||
for (auto& [entityID, data] : fluidDataMap) {
|
||||
Gfx::ODescriptorSet gridParams = gridParamsLayout->allocateDescriptorSet();
|
||||
gridParams->updateConstants("gridSize", 0, &data.gridSize);
|
||||
gridParams->writeChanges();
|
||||
Gfx::ODescriptorSet descriptorSet = descriptorLayout->allocateDescriptorSet();
|
||||
descriptorSet->updateBuffer("phi", 0, data.phi0Buffer);
|
||||
descriptorSet->updateBuffer("density", 0, data.density0Buffer);
|
||||
descriptorSet->writeChanges();
|
||||
Gfx::OComputeCommand command = graphics->createComputeCommand();
|
||||
command->bindPipeline(pipeline);
|
||||
command->bindDescriptor(descriptorSet);
|
||||
command->bindDescriptor(gridParams);
|
||||
command->dispatch((data.gridSize + threadGroupSize - UVector{1, 1, 1}) / threadGroupSize);
|
||||
graphics->executeCommands(std::move(command));
|
||||
data.phi0Buffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_TRANSFER_READ_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT);
|
||||
data.density0Buffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
|
||||
// Keep render/extraction level set in sync with injected source immediately.
|
||||
graphics->copyBuffer(data.phi0Buffer, data.phiBuffer);
|
||||
data.phiBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
data.phi0Buffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_READ_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
|
||||
// Reinitialize soon after source injection to restore signed-distance quality.
|
||||
data.frameCounter = 0;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Containers/Map.h"
|
||||
#include "Graphics/Buffer.h"
|
||||
#include "Graphics/Graphics.h"
|
||||
#include "Graphics/Resources.h"
|
||||
#include "Graphics/Shader.h"
|
||||
#include "Math/Transform.h"
|
||||
#include "Math/Vector.h"
|
||||
@@ -17,10 +18,13 @@ class FluidScene {
|
||||
virtual ~FluidScene();
|
||||
struct FluidData {
|
||||
Math::Transform transform;
|
||||
float cellSize;
|
||||
bool paused;
|
||||
float viscosity;
|
||||
float diffusion;
|
||||
float dt = 0.01f;
|
||||
UVector gridSize;
|
||||
Vector gravity;
|
||||
bool enableGravity;
|
||||
Gfx::OShaderBuffer phiBuffer;
|
||||
Gfx::OShaderBuffer phi0Buffer;
|
||||
Gfx::OShaderBuffer densityBuffer;
|
||||
@@ -49,7 +53,15 @@ class FluidScene {
|
||||
void updateFluidData(uint32 entityID, const Component::Transform& transform, const Component::FluidGrid& grid);
|
||||
const Map<uint32, FluidData>& getFluidDataMap() const { return fluidDataMap; }
|
||||
|
||||
void addSource();
|
||||
|
||||
private:
|
||||
Gfx::OPipelineLayout pipelineLayout;
|
||||
Gfx::ODescriptorLayout descriptorLayout;
|
||||
Gfx::ODescriptorLayout gridParamsLayout;
|
||||
Gfx::OComputeShader shader;
|
||||
Gfx::PComputePipeline pipeline;
|
||||
constexpr static UVector threadGroupSize = {32, 8, 1};
|
||||
Gfx::PGraphics graphics;
|
||||
Map<uint32, FluidData> fluidDataMap;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "Scene.h"
|
||||
#include "Graphics/Graphics.h"
|
||||
#include "LightEnvironment.h"
|
||||
#include "FluidScene.h"
|
||||
|
||||
using namespace Seele;
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#pragma once
|
||||
#include "MinimalEngine.h"
|
||||
#include "Graphics/Graphics.h"
|
||||
#include "LightEnvironment.h"
|
||||
#include "Physics/PhysicsSystem.h"
|
||||
#include "FluidScene.h"
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
namespace Seele {
|
||||
DECLARE_REF(Material)
|
||||
DECLARE_REF(Entity)
|
||||
DECLARE_REF(FluidScene)
|
||||
DECLARE_REF(LightEnvironment)
|
||||
class Scene {
|
||||
public:
|
||||
Scene(Gfx::PGraphics graphics);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include "FluidUpdater.h"
|
||||
#include "Graphics/DebugVertex.h"
|
||||
#include "Scene/FluidScene.h"
|
||||
|
||||
using namespace Seele;
|
||||
using namespace Seele::System;
|
||||
@@ -10,4 +12,37 @@ FluidUpdater::~FluidUpdater() {}
|
||||
void FluidUpdater::update(entt::entity id, Component::FluidGrid &grid, Component::Transform &transform) {
|
||||
auto fluidScene = scene->getFluidScene();
|
||||
fluidScene->updateFluidData((uint32)id, transform, grid);
|
||||
Vector corners[8];
|
||||
corners[0] = transform.getPosition();
|
||||
corners[1] = transform.getPosition() + Vector(transform.getScale().x, 0, 0);
|
||||
corners[2] = transform.getPosition() + Vector(0, transform.getScale().y, 0);
|
||||
corners[3] = transform.getPosition() + Vector(0, 0, transform.getScale().z);
|
||||
corners[4] = transform.getPosition() + Vector(transform.getScale().x, transform.getScale().y, 0);
|
||||
corners[5] = transform.getPosition() + Vector(transform.getScale().x, 0, transform.getScale().z);
|
||||
corners[6] = transform.getPosition() + Vector(0, transform.getScale().y, transform.getScale().z);
|
||||
corners[7] = transform.getPosition() + transform.getScale();
|
||||
const Vector debugColor(1, 0, 0);
|
||||
auto addEdge = [&](int a, int b) {
|
||||
addDebugVertex(DebugVertex{.position = corners[a], .color = debugColor});
|
||||
addDebugVertex(DebugVertex{.position = corners[b], .color = debugColor});
|
||||
};
|
||||
|
||||
// Bottom face
|
||||
addEdge(0, 1);
|
||||
addEdge(1, 4);
|
||||
addEdge(4, 2);
|
||||
addEdge(2, 0);
|
||||
|
||||
// Top face
|
||||
addEdge(3, 5);
|
||||
addEdge(5, 7);
|
||||
addEdge(7, 6);
|
||||
addEdge(6, 3);
|
||||
|
||||
// Vertical edges
|
||||
addEdge(0, 3);
|
||||
addEdge(1, 5);
|
||||
addEdge(2, 6);
|
||||
addEdge(4, 7);
|
||||
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "LightGather.h"
|
||||
#include "Scene/LightEnvironment.h"
|
||||
|
||||
using namespace Seele;
|
||||
using namespace Seele::System;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "System/LightGather.h"
|
||||
#include "System/MeshUpdater.h"
|
||||
#include "Window/Window.h"
|
||||
#include "Scene/LightEnvironment.h"
|
||||
|
||||
using namespace Seele;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user