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 x = dispatchThreadID.x + 1;
|
||||||
int y = dispatchThreadID.y + 1;
|
int y = dispatchThreadID.y + 1;
|
||||||
int z = dispatchThreadID.z + 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 dt0x = dt * (gridParams.gridSize.x - 2);
|
||||||
float dt0y = dt * (gridSize.y - 2);
|
float dt0y = dt * (gridParams.gridSize.y - 2);
|
||||||
float dt0z = dt * (gridSize.z - 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]);
|
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.x = clamp(pos.x, 0.5f, gridParams.gridSize.x - 1.5f);
|
||||||
pos.y = clamp(pos.y, 0.5f, gridSize.y - 1.5f);
|
pos.y = clamp(pos.y, 0.5f, gridParams.gridSize.y - 1.5f);
|
||||||
pos.z = clamp(pos.z, 0.5f, gridSize.z - 1.5f);
|
pos.z = clamp(pos.z, 0.5f, gridParams.gridSize.z - 1.5f);
|
||||||
|
|
||||||
int3 i0 = int3(pos);
|
int3 i0 = int3(pos);
|
||||||
int3 i1 = i0 + int3(1, 1, 1);
|
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;
|
import FluidGridData;
|
||||||
|
|
||||||
struct Params
|
struct Params {
|
||||||
{
|
|
||||||
// read-only
|
// read-only
|
||||||
FluidGridData<float> velocityX;
|
FluidGridData<float> velocityX;
|
||||||
// read-only
|
// read-only
|
||||||
@@ -17,8 +16,7 @@ ParameterBlock<Params> params;
|
|||||||
|
|
||||||
[shader("compute")]
|
[shader("compute")]
|
||||||
[numthreads(32, 8, 1)]
|
[numthreads(32, 8, 1)]
|
||||||
void computeDivergence(uint3 dispatchThreadID : SV_DispatchThreadID)
|
void computeDivergence(uint3 dispatchThreadID: SV_DispatchThreadID) {
|
||||||
{
|
|
||||||
FluidGridData<float> velocityX = params.velocityX;
|
FluidGridData<float> velocityX = params.velocityX;
|
||||||
FluidGridData<float> velocityY = params.velocityY;
|
FluidGridData<float> velocityY = params.velocityY;
|
||||||
FluidGridData<float> velocityZ = params.velocityZ;
|
FluidGridData<float> velocityZ = params.velocityZ;
|
||||||
@@ -28,8 +26,9 @@ void computeDivergence(uint3 dispatchThreadID : SV_DispatchThreadID)
|
|||||||
int x = dispatchThreadID.x + 1;
|
int x = dispatchThreadID.x + 1;
|
||||||
int y = dispatchThreadID.y + 1;
|
int y = dispatchThreadID.y + 1;
|
||||||
int z = dispatchThreadID.z + 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;
|
pressure[x, y, z] = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ ParameterBlock<Parameter> params;
|
|||||||
|
|
||||||
float getDensity(uint x, uint y, uint z)
|
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")]
|
[shader("compute")]
|
||||||
@@ -24,7 +24,7 @@ void main(uint3 dispatchThreadID : SV_DispatchThreadID)
|
|||||||
uint y = dispatchThreadID.y+1;
|
uint y = dispatchThreadID.y+1;
|
||||||
uint z = dispatchThreadID.z+1;
|
uint z = dispatchThreadID.z+1;
|
||||||
FluidGridData<float> density = params.density;
|
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] = {
|
float phi[8] = {
|
||||||
getDensity(x, y, z),
|
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>
|
struct FluidGridData<T>
|
||||||
{
|
{
|
||||||
RWStructuredBuffer<T> dataGrid;
|
RWStructuredBuffer<T> dataGrid;
|
||||||
__subscript(uint3 index) -> T
|
__subscript(uint3 index) -> T
|
||||||
{
|
{
|
||||||
get { return dataGrid[index.x + index.y * gridSize.x + index.z * gridSize.x * gridSize.y]; }
|
get { return dataGrid[index.x + index.y * gridParams.gridSize.x + index.z * gridParams.gridSize.x * gridParams.gridSize.y]; }
|
||||||
set { dataGrid[index.x + index.y * gridSize.x + index.z * gridSize.x * gridSize.y] = newValue; }
|
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
|
__subscript(uint x, uint y, uint z) -> T
|
||||||
{
|
{
|
||||||
get { return dataGrid[x + y * gridSize.x + z * gridSize.x * gridSize.y]; }
|
get { return dataGrid[x + y * gridParams.gridSize.x + z * gridParams.gridSize.x * gridParams.gridSize.y]; }
|
||||||
set { dataGrid[x + y * gridSize.x + z * gridSize.x * gridSize.y] = newValue; }
|
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 x = dispatchThreadID.x + 1;
|
||||||
int y = dispatchThreadID.y + 1;
|
int y = dispatchThreadID.y + 1;
|
||||||
int z = dispatchThreadID.z + 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;
|
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;
|
ParameterBlock<Params> params;
|
||||||
|
|
||||||
const static float isoLevel = 0.0f;
|
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)
|
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.
|
// Don't early-return — all threads must participate in barriers.
|
||||||
// Use a flag to skip work for out-of-bounds threads.
|
// 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];
|
float val[8];
|
||||||
uint cubeIndex = 0;
|
uint cubeIndex = 0;
|
||||||
@@ -169,7 +169,7 @@ void marchingCubes(uint3 dispatchThreadID : SV_DispatchThreadID, uint groupIndex
|
|||||||
float3 v0 = vertList[triTable[cubeIndex][i]];
|
float3 v0 = vertList[triTable[cubeIndex][i]];
|
||||||
float3 v1 = vertList[triTable[cubeIndex][i + 1]];
|
float3 v1 = vertList[triTable[cubeIndex][i + 1]];
|
||||||
float3 v2 = vertList[triTable[cubeIndex][i + 2]];
|
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] = v0;
|
||||||
localVertices[localOff + 1] = v1;
|
localVertices[localOff + 1] = v1;
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ void project(uint3 dispatchThreadID : SV_DispatchThreadID)
|
|||||||
int x = dispatchThreadID.x + 1;
|
int x = dispatchThreadID.x + 1;
|
||||||
int y = dispatchThreadID.y + 1;
|
int y = dispatchThreadID.y + 1;
|
||||||
int z = dispatchThreadID.z + 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;
|
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]) * gridSize.y;
|
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]) * gridSize.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
|
struct Params
|
||||||
{
|
{
|
||||||
|
float4x4 transform;
|
||||||
StructuredBuffer<float> vertexBuffer;
|
StructuredBuffer<float> vertexBuffer;
|
||||||
StructuredBuffer<float> normalBuffer;
|
StructuredBuffer<float> normalBuffer;
|
||||||
StructuredBuffer<uint> indexBuffer;
|
StructuredBuffer<uint> indexBuffer;
|
||||||
@@ -25,10 +26,12 @@ VertexOut vertexMain(uint vertexId : SV_VertexID)
|
|||||||
uint index = params.indexBuffer[vertexId];
|
uint index = params.indexBuffer[vertexId];
|
||||||
float3 vertex = float3(params.vertexBuffer[index * 3 + 0],
|
float3 vertex = float3(params.vertexBuffer[index * 3 + 0],
|
||||||
params.vertexBuffer[index * 3 + 1],
|
params.vertexBuffer[index * 3 + 1],
|
||||||
params.vertexBuffer[index * 3 + 2]) * 5;
|
params.vertexBuffer[index * 3 + 2]);
|
||||||
float3 normal = float3(params.normalBuffer[index * 3 + 0],
|
float3 normal = float3(params.normalBuffer[index * 3 + 0],
|
||||||
params.normalBuffer[index * 3 + 1],
|
params.normalBuffer[index * 3 + 1],
|
||||||
params.normalBuffer[index * 3 + 2]);
|
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_WS = vertex;
|
||||||
output.position_CS = mul(pViewParams.viewProjectionMatrix, float4(vertex, 1));
|
output.position_CS = mul(pViewParams.viewProjectionMatrix, float4(vertex, 1));
|
||||||
output.normal = normal;
|
output.normal = normal;
|
||||||
|
|||||||
@@ -14,18 +14,29 @@ void setBound(uint3 dispatchThreadID : SV_DispatchThreadID)
|
|||||||
{
|
{
|
||||||
int b = params.b;
|
int b = params.b;
|
||||||
FluidGridData<float> grid = params.grid;
|
FluidGridData<float> grid = params.grid;
|
||||||
int x = dispatchThreadID.x + 1;
|
int i = dispatchThreadID.x + 1;
|
||||||
int y = dispatchThreadID.y + 1;
|
int j = dispatchThreadID.y + 1;
|
||||||
if(x >= gridSize.x - 1 || y >= gridSize.y - 1) return;
|
|
||||||
|
|
||||||
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];
|
|
||||||
|
|
||||||
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];
|
|
||||||
|
|
||||||
grid[x, y, 0] = b == 3 ? -grid[x, y, 1] : grid[x, y, 1];
|
// X-faces: indices range over (gridSize.y, gridSize.z)
|
||||||
grid[x, y, gridSize.z - 1] = b == 3 ? -grid[x, y, gridSize.z - 2] : grid[x, y, gridSize.z - 2];
|
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];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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")]
|
[shader("compute")]
|
||||||
@@ -34,22 +45,33 @@ void setBoundEdges(uint3 dispatchThreadID : SV_DispatchThreadID)
|
|||||||
{
|
{
|
||||||
FluidGridData<float> grid = params.grid;
|
FluidGridData<float> grid = params.grid;
|
||||||
int x = dispatchThreadID.x + 1;
|
int x = dispatchThreadID.x + 1;
|
||||||
if(x >= gridSize.x - 1) return;
|
|
||||||
|
|
||||||
grid[x, 0, 0] = 0.5f * (grid[x, 1, 0] + grid[x, 0, 1]);
|
// X-axis edges: x ranges [1, gridSize.x-2]
|
||||||
grid[x, gridSize.y - 1, 0] = 0.5f * (grid[x, gridSize.y - 2, 0] + grid[x, gridSize.y - 1, 1]);
|
if(x < gridParams.gridSize.x - 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, 0, 0] = 0.5f * (grid[x, 1, 0] + grid[x, 0, 1]);
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
|
||||||
grid[0, x, 0] = 0.5f * (grid[1, x, 0] + grid[0, x, 1]);
|
// Y-axis edges: x ranges [1, gridSize.y-2]
|
||||||
grid[0, x, gridSize.z - 1] = 0.5f * (grid[1, x, gridSize.z - 1] + grid[0, x, gridSize.z - 2]);
|
if(x < gridParams.gridSize.y - 1)
|
||||||
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, 0] = 0.5f * (grid[1, x, 0] + grid[0, x, 1]);
|
||||||
|
grid[0, x, gridParams.gridSize.z - 1] = 0.5f * (grid[1, x, gridParams.gridSize.z - 1] + grid[0, x, gridParams.gridSize.z - 2]);
|
||||||
grid[0, 0, x] = 0.5f * (grid[1, 0, x] + grid[0, 1, x]);
|
grid[gridParams.gridSize.x - 1, x, 0] = 0.5f * (grid[gridParams.gridSize.x - 2, x, 0] + grid[gridParams.gridSize.x - 1, x, 1]);
|
||||||
grid[0, gridSize.y - 1, x] = 0.5f * (grid[1, gridSize.y - 1, x] + grid[0, gridSize.y - 2, x]);
|
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]);
|
||||||
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]);
|
|
||||||
|
// 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, 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")]
|
[shader("compute")]
|
||||||
@@ -59,13 +81,13 @@ void setBoundCorners(uint3 dispatchThreadID : SV_DispatchThreadID)
|
|||||||
FluidGridData<float> grid = params.grid;
|
FluidGridData<float> grid = params.grid;
|
||||||
uint threadIdx = dispatchThreadID.x;
|
uint threadIdx = dispatchThreadID.x;
|
||||||
|
|
||||||
uint x = ((threadIdx & 1) == 0) ? 0 : (gridSize.x - 1);
|
uint x = ((threadIdx & 1) == 0) ? 0 : (gridParams.gridSize.x - 1);
|
||||||
uint y = ((threadIdx & 2) == 0) ? 0 : (gridSize.y - 1);
|
uint y = ((threadIdx & 2) == 0) ? 0 : (gridParams.gridSize.y - 1);
|
||||||
uint z = ((threadIdx & 4) == 0) ? 0 : (gridSize.z - 1);
|
uint z = ((threadIdx & 4) == 0) ? 0 : (gridParams.gridSize.z - 1);
|
||||||
|
|
||||||
uint nx = (x == 0) ? 1 : (gridSize.x - 2);
|
uint nx = (x == 0) ? 1 : (gridParams.gridSize.x - 2);
|
||||||
uint ny = (y == 0) ? 1 : (gridSize.y - 2);
|
uint ny = (y == 0) ? 1 : (gridParams.gridSize.y - 2);
|
||||||
uint nz = (z == 0) ? 1 : (gridSize.z - 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;
|
uint z = dispatchThreadID.z + 1;
|
||||||
FluidGridData<float> phi = params.phi;
|
FluidGridData<float> phi = params.phi;
|
||||||
FluidGridData<float> phi0 = params.phi0;
|
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 dtau = params.dtau;
|
||||||
float dx = 1.0f;
|
float dx = 1.0f;
|
||||||
|
|||||||
@@ -4,10 +4,13 @@
|
|||||||
namespace Seele {
|
namespace Seele {
|
||||||
namespace Component {
|
namespace Component {
|
||||||
struct FluidGrid {
|
struct FluidGrid {
|
||||||
float cellSize = 1.0f;
|
bool paused = true;
|
||||||
float viscosity = 0.1f;
|
float dt = 0.1f;
|
||||||
float diffusion = 0.01f;
|
float viscosity = 0.001f;
|
||||||
|
float diffusion = 0.0001f;
|
||||||
UVector gridSize = {128, 128, 128};
|
UVector gridSize = {128, 128, 128};
|
||||||
|
Vector gravity = {0.0f, -9.81f, 0.0f};
|
||||||
|
bool enableGravity = true;
|
||||||
};
|
};
|
||||||
} // namespace Component
|
} // namespace Component
|
||||||
} // namespace Seele
|
} // namespace Seele
|
||||||
@@ -1,19 +1,26 @@
|
|||||||
#include "FluidRenderPass.h"
|
#include "FluidRenderPass.h"
|
||||||
#include "Component/Transform.h"
|
#include "Component/Transform.h"
|
||||||
#include "Graphics/Command.h"
|
#include "Graphics/Command.h"
|
||||||
|
#include "Graphics/Descriptor.h"
|
||||||
#include "Graphics/Enums.h"
|
#include "Graphics/Enums.h"
|
||||||
#include "Graphics/Graphics.h"
|
#include "Graphics/Graphics.h"
|
||||||
#include "Graphics/Initializer.h"
|
#include "Graphics/Initializer.h"
|
||||||
#include "Graphics/RenderTarget.h"
|
#include "Graphics/RenderTarget.h"
|
||||||
#include "Graphics/Shader.h"
|
#include "Graphics/Shader.h"
|
||||||
|
#include "Math/Matrix.h"
|
||||||
#include "Scene/LightEnvironment.h"
|
#include "Scene/LightEnvironment.h"
|
||||||
#include "Scene/Scene.h"
|
#include "Scene/Scene.h"
|
||||||
|
#include "Scene/FluidScene.h"
|
||||||
|
|
||||||
using namespace Seele;
|
using namespace Seele;
|
||||||
|
|
||||||
FluidRenderPass::FluidRenderPass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graphics), scene(scene) {
|
FluidRenderPass::FluidRenderPass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graphics), scene(scene) {
|
||||||
pipelineLayout = graphics->createPipelineLayout("FluidPipelineLayout");
|
pipelineLayout = graphics->createPipelineLayout("FluidPipelineLayout");
|
||||||
descriptorLayout = graphics->createDescriptorLayout("params");
|
descriptorLayout = graphics->createDescriptorLayout("params");
|
||||||
|
descriptorLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||||
|
.name = "transform",
|
||||||
|
.uniformLength = sizeof(Matrix4),
|
||||||
|
});
|
||||||
descriptorLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
descriptorLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||||
.name = "vertexBuffer",
|
.name = "vertexBuffer",
|
||||||
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||||
@@ -54,6 +61,8 @@ void FluidRenderPass::render() {
|
|||||||
descriptorLayout->reset();
|
descriptorLayout->reset();
|
||||||
for (const auto& [id, data] : scene->getFluidScene()->getFluidDataMap()) {
|
for (const auto& [id, data] : scene->getFluidScene()->getFluidDataMap()) {
|
||||||
descriptorSet = descriptorLayout->allocateDescriptorSet();
|
descriptorSet = descriptorLayout->allocateDescriptorSet();
|
||||||
|
Matrix4 transformMatrix = data.transform.toMatrix();
|
||||||
|
descriptorSet->updateConstants("transform", 0, &transformMatrix);
|
||||||
descriptorSet->updateBuffer("vertexBuffer", 0, data.vertexBuffer);
|
descriptorSet->updateBuffer("vertexBuffer", 0, data.vertexBuffer);
|
||||||
descriptorSet->updateBuffer("normalBuffer", 0, data.normalBuffer);
|
descriptorSet->updateBuffer("normalBuffer", 0, data.normalBuffer);
|
||||||
descriptorSet->updateBuffer("indexBuffer", 0, data.indexBuffer);
|
descriptorSet->updateBuffer("indexBuffer", 0, data.indexBuffer);
|
||||||
@@ -75,6 +84,7 @@ void FluidRenderPass::endFrame() {}
|
|||||||
void FluidRenderPass::publishOutputs() {
|
void FluidRenderPass::publishOutputs() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FluidRenderPass::createRenderPass() {
|
void FluidRenderPass::createRenderPass() {
|
||||||
colorAttachment = resources->requestRenderTarget("BASEPASS_COLOR");
|
colorAttachment = resources->requestRenderTarget("BASEPASS_COLOR");
|
||||||
colorAttachment.setLoadOp(Gfx::SE_ATTACHMENT_LOAD_OP_LOAD);
|
colorAttachment.setLoadOp(Gfx::SE_ATTACHMENT_LOAD_OP_LOAD);
|
||||||
@@ -112,6 +122,7 @@ void FluidRenderPass::createRenderPass() {
|
|||||||
Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
renderPass = graphics->createRenderPass(layout, dependency, viewport->getRenderArea(), "FluidRenderPass");
|
renderPass = graphics->createRenderPass(layout, dependency, viewport->getRenderArea(), "FluidRenderPass");
|
||||||
pipeline = graphics->createGraphicsPipeline(Gfx::LegacyPipelineCreateInfo{
|
pipeline = graphics->createGraphicsPipeline(Gfx::LegacyPipelineCreateInfo{
|
||||||
.vertexShader = vertexShader,
|
.vertexShader = vertexShader,
|
||||||
@@ -124,7 +135,7 @@ void FluidRenderPass::createRenderPass() {
|
|||||||
},
|
},
|
||||||
.rasterizationState =
|
.rasterizationState =
|
||||||
{
|
{
|
||||||
.cullMode = Gfx::SE_CULL_MODE_FRONT_BIT,
|
.cullMode = Gfx::SE_CULL_MODE_NONE,
|
||||||
},
|
},
|
||||||
.colorBlend =
|
.colorBlend =
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "Math/Vector.h"
|
#include "Math/Vector.h"
|
||||||
#include "RenderGraph.h"
|
#include "RenderGraph.h"
|
||||||
#include "Scene/Scene.h"
|
#include "Scene/Scene.h"
|
||||||
|
#include "Scene/LightEnvironment.h"
|
||||||
|
|
||||||
using namespace Seele;
|
using namespace Seele;
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "Graphics/StaticMeshVertexData.h"
|
#include "Graphics/StaticMeshVertexData.h"
|
||||||
#include "Material/Material.h"
|
#include "Material/Material.h"
|
||||||
#include "Material/MaterialInstance.h"
|
#include "Material/MaterialInstance.h"
|
||||||
|
#include "Scene/LightEnvironment.h"
|
||||||
#include "RenderPass.h"
|
#include "RenderPass.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "Graphics/Initializer.h"
|
#include "Graphics/Initializer.h"
|
||||||
#include "Graphics/Shader.h"
|
#include "Graphics/Shader.h"
|
||||||
#include "Math/Matrix.h"
|
#include "Math/Matrix.h"
|
||||||
|
#include "Scene/LightEnvironment.h"
|
||||||
#include <glm/ext/matrix_transform.hpp>
|
#include <glm/ext/matrix_transform.hpp>
|
||||||
#include <glm/matrix.hpp>
|
#include <glm/matrix.hpp>
|
||||||
|
|
||||||
|
|||||||
@@ -7,13 +7,18 @@
|
|||||||
#include "Graphics/Initializer.h"
|
#include "Graphics/Initializer.h"
|
||||||
#include "Graphics/Shader.h"
|
#include "Graphics/Shader.h"
|
||||||
#include "Math/Vector.h"
|
#include "Math/Vector.h"
|
||||||
#include <iostream>
|
#include "Scene/FluidScene.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
using namespace Seele;
|
using namespace Seele;
|
||||||
|
|
||||||
constexpr static int reinitInterval = 5;
|
// Reinitialization is in pseudo-time; keep it gentle to avoid eroding the interface each frame.
|
||||||
constexpr static int reinitIterations = 5;
|
constexpr static int reinitInterval = 20;
|
||||||
constexpr static float reinitDtau = 0.5f;
|
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) \
|
#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) {
|
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.pipelineLayout = graphics->createPipelineLayout("SetBoundsPipelineLayout");
|
||||||
setBounds.descriptorLayout = graphics->createDescriptorLayout("params");
|
setBounds.descriptorLayout = graphics->createDescriptorLayout("params");
|
||||||
@@ -36,6 +47,7 @@ SimulationComputePass::SimulationComputePass(Gfx::PGraphics graphics, PScene sce
|
|||||||
});
|
});
|
||||||
setBounds.descriptorLayout->create();
|
setBounds.descriptorLayout->create();
|
||||||
setBounds.pipelineLayout->addDescriptorLayout(setBounds.descriptorLayout);
|
setBounds.pipelineLayout->addDescriptorLayout(setBounds.descriptorLayout);
|
||||||
|
setBounds.pipelineLayout->addDescriptorLayout(gridSizeLayout);
|
||||||
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
||||||
.name = "SetBound",
|
.name = "SetBound",
|
||||||
.modules = {"SetBound"},
|
.modules = {"SetBound"},
|
||||||
@@ -84,6 +96,7 @@ SimulationComputePass::SimulationComputePass(Gfx::PGraphics graphics, PScene sce
|
|||||||
});
|
});
|
||||||
linearSolve.descriptorLayout->create();
|
linearSolve.descriptorLayout->create();
|
||||||
linearSolve.pipelineLayout->addDescriptorLayout(linearSolve.descriptorLayout);
|
linearSolve.pipelineLayout->addDescriptorLayout(linearSolve.descriptorLayout);
|
||||||
|
linearSolve.pipelineLayout->addDescriptorLayout(gridSizeLayout);
|
||||||
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
||||||
.name = "LinearSolve",
|
.name = "LinearSolve",
|
||||||
.modules = {"LinearSolve"},
|
.modules = {"LinearSolve"},
|
||||||
@@ -122,6 +135,7 @@ SimulationComputePass::SimulationComputePass(Gfx::PGraphics graphics, PScene sce
|
|||||||
});
|
});
|
||||||
computeDivergence.descriptorLayout->create();
|
computeDivergence.descriptorLayout->create();
|
||||||
computeDivergence.pipelineLayout->addDescriptorLayout(computeDivergence.descriptorLayout);
|
computeDivergence.pipelineLayout->addDescriptorLayout(computeDivergence.descriptorLayout);
|
||||||
|
computeDivergence.pipelineLayout->addDescriptorLayout(gridSizeLayout);
|
||||||
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
||||||
.name = "Divergence",
|
.name = "Divergence",
|
||||||
.modules = {"Divergence"},
|
.modules = {"Divergence"},
|
||||||
@@ -157,6 +171,7 @@ SimulationComputePass::SimulationComputePass(Gfx::PGraphics graphics, PScene sce
|
|||||||
});
|
});
|
||||||
project.descriptorLayout->create();
|
project.descriptorLayout->create();
|
||||||
project.pipelineLayout->addDescriptorLayout(project.descriptorLayout);
|
project.pipelineLayout->addDescriptorLayout(project.descriptorLayout);
|
||||||
|
project.pipelineLayout->addDescriptorLayout(gridSizeLayout);
|
||||||
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
||||||
.name = "Project",
|
.name = "Project",
|
||||||
.modules = {"Project"},
|
.modules = {"Project"},
|
||||||
@@ -199,6 +214,7 @@ SimulationComputePass::SimulationComputePass(Gfx::PGraphics graphics, PScene sce
|
|||||||
});
|
});
|
||||||
advect.descriptorLayout->create();
|
advect.descriptorLayout->create();
|
||||||
advect.pipelineLayout->addDescriptorLayout(advect.descriptorLayout);
|
advect.pipelineLayout->addDescriptorLayout(advect.descriptorLayout);
|
||||||
|
advect.pipelineLayout->addDescriptorLayout(gridSizeLayout);
|
||||||
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
||||||
.name = "Advect",
|
.name = "Advect",
|
||||||
.modules = {"Advect"},
|
.modules = {"Advect"},
|
||||||
@@ -230,7 +246,7 @@ SimulationComputePass::SimulationComputePass(Gfx::PGraphics graphics, PScene sce
|
|||||||
});
|
});
|
||||||
reinitialize.descriptorLayout->create();
|
reinitialize.descriptorLayout->create();
|
||||||
reinitialize.pipelineLayout->addDescriptorLayout(reinitialize.descriptorLayout);
|
reinitialize.pipelineLayout->addDescriptorLayout(reinitialize.descriptorLayout);
|
||||||
|
reinitialize.pipelineLayout->addDescriptorLayout(gridSizeLayout);
|
||||||
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
||||||
.name = "SignedDistance",
|
.name = "SignedDistance",
|
||||||
.modules = {"SignedDistance"},
|
.modules = {"SignedDistance"},
|
||||||
@@ -244,6 +260,45 @@ SimulationComputePass::SimulationComputePass(Gfx::PGraphics graphics, PScene sce
|
|||||||
.pipelineLayout = reinitialize.pipelineLayout,
|
.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() {}
|
SimulationComputePass::~SimulationComputePass() {}
|
||||||
@@ -255,13 +310,21 @@ void SimulationComputePass::beginFrame(const Seele::Component::Camera&, const Se
|
|||||||
project.descriptorLayout->reset();
|
project.descriptorLayout->reset();
|
||||||
advect.descriptorLayout->reset();
|
advect.descriptorLayout->reset();
|
||||||
reinitialize.descriptorLayout->reset();
|
reinitialize.descriptorLayout->reset();
|
||||||
|
applyForces.descriptorLayout->reset();
|
||||||
|
gridSizeLayout->reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulationComputePass::render() {
|
void SimulationComputePass::render() {
|
||||||
for (auto& [entityID, data] : scene->getFluidScene()->getFluidDataMap()) {
|
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");
|
graphics->beginDebugRegion("Diffuse");
|
||||||
for (uint iteration = 0; iteration < 4; ++iteration) {
|
for (int iteration = 0; iteration < velocityDiffuseIterations; ++iteration) {
|
||||||
float a = dt * data.viscosity * (data.gridSize.x - 2) * (data.gridSize.y - 2) * (data.gridSize.z - 2);
|
float a = data.dt * data.viscosity * (data.gridSize.x - 2) * (data.gridSize.x - 2);
|
||||||
float c = 1 + 6 * a;
|
float c = 1 + 6 * a;
|
||||||
linearSolvePass(data.velocityXNextBuffer, data.velocityXBuffer, data.velocityX0Buffer, a, c, data.gridSize);
|
linearSolvePass(data.velocityXNextBuffer, data.velocityXBuffer, data.velocityX0Buffer, a, c, data.gridSize);
|
||||||
linearSolvePass(data.velocityYNextBuffer, data.velocityYBuffer, data.velocityY0Buffer, 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;
|
Gfx::PShaderBuffer pressureNext = data.velocityZBuffer;
|
||||||
divergencePass(divergence, pressureCurrent, data.velocityX0Buffer, data.velocityY0Buffer, data.velocityZ0Buffer, data.gridSize);
|
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);
|
linearSolvePass(pressureNext, pressureCurrent, divergence, 1, 6, data.gridSize);
|
||||||
|
|
||||||
setBoundsPass(pressureNext, 0, data.gridSize);
|
setBoundsPass(pressureNext, 0, data.gridSize);
|
||||||
@@ -304,15 +367,38 @@ void SimulationComputePass::render() {
|
|||||||
graphics->endDebugRegion();
|
graphics->endDebugRegion();
|
||||||
|
|
||||||
graphics->beginDebugRegion("Advect");
|
graphics->beginDebugRegion("Advect");
|
||||||
advectPass(data.velocityXBuffer, data.velocityX0Buffer, data.velocityX0Buffer, data.velocityY0Buffer, data.velocityZ0Buffer, dt, data.gridSize);
|
advectPass(data.velocityXBuffer, data.velocityX0Buffer, data.velocityX0Buffer, data.velocityY0Buffer, data.velocityZ0Buffer, data.dt,
|
||||||
advectPass(data.velocityYBuffer, data.velocityY0Buffer, data.velocityX0Buffer, data.velocityY0Buffer, data.velocityZ0Buffer, dt, data.gridSize);
|
data.gridSize);
|
||||||
advectPass(data.velocityZBuffer, data.velocityZ0Buffer, data.velocityX0Buffer, data.velocityY0Buffer, data.velocityZ0Buffer, 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.velocityXBuffer, 1, data.gridSize);
|
||||||
setBoundsPass(data.velocityYBuffer, 2, data.gridSize);
|
setBoundsPass(data.velocityYBuffer, 2, data.gridSize);
|
||||||
setBoundsPass(data.velocityZBuffer, 3, data.gridSize);
|
setBoundsPass(data.velocityZBuffer, 3, data.gridSize);
|
||||||
graphics->endDebugRegion();
|
graphics->endDebugRegion();
|
||||||
|
|
||||||
// swap velocity buffers
|
// swap velocity buffers
|
||||||
SWAP(data.velocityX0Buffer, data.velocityXBuffer);
|
SWAP(data.velocityX0Buffer, data.velocityXBuffer);
|
||||||
SWAP(data.velocityY0Buffer, data.velocityYBuffer);
|
SWAP(data.velocityY0Buffer, data.velocityYBuffer);
|
||||||
@@ -326,8 +412,8 @@ void SimulationComputePass::render() {
|
|||||||
graphics->copyBuffer(density0, densityCurrent);
|
graphics->copyBuffer(density0, densityCurrent);
|
||||||
densityCurrent->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT,
|
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);
|
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||||
for (int iteration = 0; iteration < 4; ++iteration) {
|
for (int iteration = 0; iteration < densityDiffuseIterations; ++iteration) {
|
||||||
float a = dt * data.diffusion * (data.gridSize.x - 2) * (data.gridSize.y - 2) * (data.gridSize.z - 2);
|
float a = data.dt * data.diffusion * (data.gridSize.x - 2) * (data.gridSize.x - 2);
|
||||||
float c = 1 + 6 * a;
|
float c = 1 + 6 * a;
|
||||||
linearSolvePass(densityNext, densityCurrent, density0, a, c, data.gridSize);
|
linearSolvePass(densityNext, densityCurrent, density0, a, c, data.gridSize);
|
||||||
setBoundsPass(densityNext, 0, data.gridSize);
|
setBoundsPass(densityNext, 0, data.gridSize);
|
||||||
@@ -335,12 +421,13 @@ void SimulationComputePass::render() {
|
|||||||
}
|
}
|
||||||
graphics->endDebugRegion();
|
graphics->endDebugRegion();
|
||||||
graphics->beginDebugRegion("AdvectDensity");
|
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);
|
setBoundsPass(data.density0Buffer, 0, data.gridSize);
|
||||||
graphics->endDebugRegion();
|
graphics->endDebugRegion();
|
||||||
|
|
||||||
graphics->beginDebugRegion("AdvectLevelSet");
|
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);
|
setBoundsPass(data.phiBuffer, 0, data.gridSize);
|
||||||
|
|
||||||
// Reinitialize level set every N frames to restore |grad phi| = 1
|
// 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();
|
Gfx::OComputeCommand boundsCommand = graphics->createComputeCommand();
|
||||||
boundsCommand->bindPipeline(setBounds.pipeline);
|
boundsCommand->bindPipeline(setBounds.pipeline);
|
||||||
boundsCommand->bindDescriptor(bounds);
|
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));
|
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,
|
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();
|
Gfx::OComputeCommand edgesCommand = graphics->createComputeCommand();
|
||||||
edgesCommand->bindPipeline(setBounds.pipelineEdges);
|
edgesCommand->bindPipeline(setBounds.pipelineEdges);
|
||||||
edgesCommand->bindDescriptor(bounds);
|
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));
|
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,
|
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();
|
Gfx::OComputeCommand cornersCommand = graphics->createComputeCommand();
|
||||||
cornersCommand->bindPipeline(setBounds.pipelineCorners);
|
cornersCommand->bindPipeline(setBounds.pipelineCorners);
|
||||||
cornersCommand->bindDescriptor(bounds);
|
cornersCommand->bindDescriptor(bounds);
|
||||||
|
cornersCommand->bindDescriptor(gridSizeSet);
|
||||||
cornersCommand->dispatch(1, 1, 1);
|
cornersCommand->dispatch(1, 1, 1);
|
||||||
graphics->executeCommands(std::move(cornersCommand));
|
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);
|
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();
|
Gfx::ODescriptorSet solve = linearSolve.descriptorLayout->allocateDescriptorSet();
|
||||||
solve->updateBuffer("next", 0, next);
|
solve->updateBuffer("next", 0, next);
|
||||||
solve->updateBuffer("current", 0, current);
|
solve->updateBuffer("current", 0, current);
|
||||||
@@ -416,6 +512,7 @@ void SimulationComputePass::linearSolvePass(Gfx::PShaderBuffer next, Gfx::PShade
|
|||||||
Gfx::OComputeCommand solveCommand = graphics->createComputeCommand();
|
Gfx::OComputeCommand solveCommand = graphics->createComputeCommand();
|
||||||
solveCommand->bindPipeline(linearSolve.pipeline);
|
solveCommand->bindPipeline(linearSolve.pipeline);
|
||||||
solveCommand->bindDescriptor(solve);
|
solveCommand->bindDescriptor(solve);
|
||||||
|
solveCommand->bindDescriptor(gridSizeSet);
|
||||||
solveCommand->dispatch(getDispatchSize(gridSize, linearSolve.threadGroupSize));
|
solveCommand->dispatch(getDispatchSize(gridSize, linearSolve.threadGroupSize));
|
||||||
graphics->executeCommands(std::move(solveCommand));
|
graphics->executeCommands(std::move(solveCommand));
|
||||||
|
|
||||||
@@ -435,6 +532,7 @@ void SimulationComputePass::divergencePass(Seele::Gfx::PShaderBuffer divergence,
|
|||||||
Gfx::OComputeCommand divergenceCommand = graphics->createComputeCommand();
|
Gfx::OComputeCommand divergenceCommand = graphics->createComputeCommand();
|
||||||
divergenceCommand->bindPipeline(computeDivergence.pipeline);
|
divergenceCommand->bindPipeline(computeDivergence.pipeline);
|
||||||
divergenceCommand->bindDescriptor(divergenceSet);
|
divergenceCommand->bindDescriptor(divergenceSet);
|
||||||
|
divergenceCommand->bindDescriptor(gridSizeSet);
|
||||||
divergenceCommand->dispatch(getDispatchSize(gridSize, computeDivergence.threadGroupSize));
|
divergenceCommand->dispatch(getDispatchSize(gridSize, computeDivergence.threadGroupSize));
|
||||||
graphics->executeCommands(std::move(divergenceCommand));
|
graphics->executeCommands(std::move(divergenceCommand));
|
||||||
// divergence is now in velocityXBuffer, pressure is in velocityYBuffer
|
// 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();
|
Gfx::OComputeCommand projectCommand = graphics->createComputeCommand();
|
||||||
projectCommand->bindPipeline(project.pipeline);
|
projectCommand->bindPipeline(project.pipeline);
|
||||||
projectCommand->bindDescriptor(projectSet);
|
projectCommand->bindDescriptor(projectSet);
|
||||||
|
projectCommand->bindDescriptor(gridSizeSet);
|
||||||
projectCommand->dispatch(getDispatchSize(gridSize, project.threadGroupSize));
|
projectCommand->dispatch(getDispatchSize(gridSize, project.threadGroupSize));
|
||||||
graphics->executeCommands(std::move(projectCommand));
|
graphics->executeCommands(std::move(projectCommand));
|
||||||
|
|
||||||
@@ -479,6 +578,7 @@ void SimulationComputePass::advectPass(Gfx::PShaderBuffer quantity, Gfx::PShader
|
|||||||
Gfx::OComputeCommand advectCommand = graphics->createComputeCommand();
|
Gfx::OComputeCommand advectCommand = graphics->createComputeCommand();
|
||||||
advectCommand->bindPipeline(advect.pipeline);
|
advectCommand->bindPipeline(advect.pipeline);
|
||||||
advectCommand->bindDescriptor(advectSet);
|
advectCommand->bindDescriptor(advectSet);
|
||||||
|
advectCommand->bindDescriptor(gridSizeSet);
|
||||||
advectCommand->dispatch(getDispatchSize(gridSize, advect.threadGroupSize));
|
advectCommand->dispatch(getDispatchSize(gridSize, advect.threadGroupSize));
|
||||||
graphics->executeCommands(std::move(advectCommand));
|
graphics->executeCommands(std::move(advectCommand));
|
||||||
|
|
||||||
@@ -486,6 +586,29 @@ void SimulationComputePass::advectPass(Gfx::PShaderBuffer quantity, Gfx::PShader
|
|||||||
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
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) {
|
void SimulationComputePass::reinitializeLevelSetPass(Seele::Gfx::PShaderBuffer phi, Seele::Gfx::PShaderBuffer phi0, UVector gridSize) {
|
||||||
graphics->beginDebugRegion("ReinitializeLevelSet");
|
graphics->beginDebugRegion("ReinitializeLevelSet");
|
||||||
// Snapshot current phi into phi0 for the sign function
|
// 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();
|
Gfx::OComputeCommand reinitCommand = graphics->createComputeCommand();
|
||||||
reinitCommand->bindPipeline(reinitialize.pipeline);
|
reinitCommand->bindPipeline(reinitialize.pipeline);
|
||||||
reinitCommand->bindDescriptor(reinitSet);
|
reinitCommand->bindDescriptor(reinitSet);
|
||||||
|
reinitCommand->bindDescriptor(gridSizeSet);
|
||||||
reinitCommand->dispatch(getDispatchSize(gridSize, reinitialize.threadGroupSize));
|
reinitCommand->dispatch(getDispatchSize(gridSize, reinitialize.threadGroupSize));
|
||||||
graphics->executeCommands(std::move(reinitCommand));
|
graphics->executeCommands(std::move(reinitCommand));
|
||||||
|
|
||||||
|
|||||||
@@ -75,8 +75,17 @@ class SimulationComputePass : public RenderPass {
|
|||||||
Gfx::PComputePipeline pipeline;
|
Gfx::PComputePipeline pipeline;
|
||||||
constexpr static UVector threadGroupSize = {32, 8, 1};
|
constexpr static UVector threadGroupSize = {32, 8, 1};
|
||||||
} reinitialize;
|
} 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;
|
PScene scene;
|
||||||
constexpr static float dt = 0.1f;
|
|
||||||
};
|
};
|
||||||
DEFINE_REF(SimulationComputePass)
|
DEFINE_REF(SimulationComputePass)
|
||||||
} // namespace Seele
|
} // namespace Seele
|
||||||
@@ -5,21 +5,18 @@
|
|||||||
#include "Graphics/Graphics.h"
|
#include "Graphics/Graphics.h"
|
||||||
#include "Graphics/Initializer.h"
|
#include "Graphics/Initializer.h"
|
||||||
#include "Graphics/Shader.h"
|
#include "Graphics/Shader.h"
|
||||||
#include "Math/Vector.h"
|
#include "Scene/FluidScene.h"
|
||||||
|
|
||||||
using namespace Seele;
|
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) {
|
SurfaceExtractPass::SurfaceExtractPass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graphics), scene(scene) {
|
||||||
pipelineLayout = graphics->createPipelineLayout("SurfaceExtractPipelineLayout");
|
pipelineLayout = graphics->createPipelineLayout("SurfaceExtractPipelineLayout");
|
||||||
|
gridSizeLayout = graphics->createDescriptorLayout("gridParams");
|
||||||
|
gridSizeLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||||
|
.name = "gridSize",
|
||||||
|
.uniformLength = sizeof(UVector),
|
||||||
|
});
|
||||||
|
gridSizeLayout->create();
|
||||||
descriptorLayout = graphics->createDescriptorLayout("params");
|
descriptorLayout = graphics->createDescriptorLayout("params");
|
||||||
descriptorLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
descriptorLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||||
.name = "vertexBuffer",
|
.name = "vertexBuffer",
|
||||||
@@ -43,6 +40,7 @@ SurfaceExtractPass::SurfaceExtractPass(Gfx::PGraphics graphics, PScene scene) :
|
|||||||
});
|
});
|
||||||
descriptorLayout->create();
|
descriptorLayout->create();
|
||||||
pipelineLayout->addDescriptorLayout(descriptorLayout);
|
pipelineLayout->addDescriptorLayout(descriptorLayout);
|
||||||
|
pipelineLayout->addDescriptorLayout(gridSizeLayout);
|
||||||
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
||||||
.name = "MarchingCubes",
|
.name = "MarchingCubes",
|
||||||
.modules = {"MarchingCubes"},
|
.modules = {"MarchingCubes"},
|
||||||
@@ -62,8 +60,12 @@ SurfaceExtractPass::~SurfaceExtractPass() {}
|
|||||||
|
|
||||||
void SurfaceExtractPass::beginFrame(const Seele::Component::Camera&, const Seele::Component::Transform&) {}
|
void SurfaceExtractPass::beginFrame(const Seele::Component::Camera&, const Seele::Component::Transform&) {}
|
||||||
|
|
||||||
|
|
||||||
void SurfaceExtractPass::render() {
|
void SurfaceExtractPass::render() {
|
||||||
for (auto& [entityID, data] : scene->getFluidScene()->getFluidDataMap()) {
|
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.vertexBuffer->rotateBuffer(data.getVertexBufferSize() * sizeof(float));
|
||||||
data.normalBuffer->rotateBuffer(data.getVertexBufferSize() * sizeof(float));
|
data.normalBuffer->rotateBuffer(data.getVertexBufferSize() * sizeof(float));
|
||||||
data.indexBuffer->rotateBuffer(data.getIndexBufferSize() * sizeof(uint32));
|
data.indexBuffer->rotateBuffer(data.getIndexBufferSize() * sizeof(uint32));
|
||||||
@@ -83,6 +85,7 @@ void SurfaceExtractPass::render() {
|
|||||||
Gfx::OComputeCommand cmd = graphics->createComputeCommand();
|
Gfx::OComputeCommand cmd = graphics->createComputeCommand();
|
||||||
cmd->bindPipeline(pipeline);
|
cmd->bindPipeline(pipeline);
|
||||||
cmd->bindDescriptor(descriptorSet);
|
cmd->bindDescriptor(descriptorSet);
|
||||||
|
cmd->bindDescriptor(gridSizeSet);
|
||||||
cmd->dispatch((data.gridSize + threadGroupSize - 1u) / threadGroupSize);
|
cmd->dispatch((data.gridSize + threadGroupSize - 1u) / threadGroupSize);
|
||||||
graphics->executeCommands(std::move(cmd));
|
graphics->executeCommands(std::move(cmd));
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ private:
|
|||||||
|
|
||||||
Gfx::OPipelineLayout pipelineLayout;
|
Gfx::OPipelineLayout pipelineLayout;
|
||||||
Gfx::ODescriptorLayout descriptorLayout;
|
Gfx::ODescriptorLayout descriptorLayout;
|
||||||
|
Gfx::ODescriptorLayout gridSizeLayout;
|
||||||
Gfx::ODescriptorSet descriptorSet;
|
Gfx::ODescriptorSet descriptorSet;
|
||||||
Gfx::OComputeShader computeShader;
|
Gfx::OComputeShader computeShader;
|
||||||
Gfx::PComputePipeline pipeline;
|
Gfx::PComputePipeline pipeline;
|
||||||
|
|||||||
@@ -848,6 +848,7 @@ void Graphics::pickPhysicalDevice() {
|
|||||||
|
|
||||||
vkGetPhysicalDeviceProperties2(physicalDevice, &props.get());
|
vkGetPhysicalDeviceProperties2(physicalDevice, &props.get());
|
||||||
features.get<VkPhysicalDeviceFeatures2>().features = {
|
features.get<VkPhysicalDeviceFeatures2>().features = {
|
||||||
|
// .robustBufferAccess = true,
|
||||||
.geometryShader = true,
|
.geometryShader = true,
|
||||||
.sampleRateShading = true,
|
.sampleRateShading = true,
|
||||||
.fillModeNonSolid = true,
|
.fillModeNonSolid = true,
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#include "slang-compile.h"
|
#include "slang-compile.h"
|
||||||
#include "Containers/Array.h"
|
#include "Containers/Array.h"
|
||||||
#include "Graphics/Descriptor.h"
|
#include "Graphics/Descriptor.h"
|
||||||
|
#include <array>
|
||||||
|
#include <cstdlib>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -29,113 +31,54 @@ thread_local Slang::ComPtr<slang::ISession> session;
|
|||||||
thread_local Array<std::string> entryPoints;
|
thread_local Array<std::string> entryPoints;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
std::filesystem::path getExecutableDirectory() {
|
void appendEnvPath(const char* varName, const std::filesystem::path& path) {
|
||||||
std::error_code error;
|
if (!std::filesystem::exists(path) || !std::filesystem::is_directory(path)) {
|
||||||
auto exePath = std::filesystem::read_symlink("/proc/self/exe", error);
|
return;
|
||||||
if (!error) {
|
|
||||||
return exePath.parent_path();
|
|
||||||
}
|
}
|
||||||
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) {
|
for (const auto& candidate : candidates) {
|
||||||
std::error_code error;
|
appendEnvPath("LD_LIBRARY_PATH", candidate);
|
||||||
if (std::filesystem::exists(candidate, error) && std::filesystem::is_directory(candidate, error)) {
|
appendEnvPath("PATH", candidate);
|
||||||
return 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) {
|
void Seele::beginCompilation(const ShaderCompilationInfo& info, SlangCompileTarget target, Gfx::PPipelineLayout layout) {
|
||||||
if (!globalSession) {
|
if (!globalSession) {
|
||||||
|
configureSlangRuntimeEnv();
|
||||||
SlangGlobalSessionDesc sessionDesc = {};
|
SlangGlobalSessionDesc sessionDesc = {};
|
||||||
sessionDesc.enableGLSL = true;
|
sessionDesc.enableGLSL = true;
|
||||||
slang::createGlobalSession(&sessionDesc, globalSession.writeRef());
|
slang::createGlobalSession(&sessionDesc, globalSession.writeRef());
|
||||||
configureDownstreamCompilers(globalSession);
|
|
||||||
}
|
}
|
||||||
slang::SessionDesc sessionDesc;
|
slang::SessionDesc sessionDesc;
|
||||||
sessionDesc.flags = 0;
|
sessionDesc.flags = 0;
|
||||||
@@ -156,6 +99,22 @@ void Seele::beginCompilation(const ShaderCompilationInfo& info, SlangCompileTarg
|
|||||||
.intValue0 = SLANG_OPTIMIZATION_LEVEL_NONE,
|
.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,
|
.name = slang::CompilerOptionName::SkipSPIRVValidation,
|
||||||
.value =
|
.value =
|
||||||
|
|||||||
+112
-40
@@ -1,9 +1,45 @@
|
|||||||
#include "FluidScene.h"
|
#include "FluidScene.h"
|
||||||
|
#include "Graphics/Command.h"
|
||||||
|
#include "Graphics/Descriptor.h"
|
||||||
#include "Graphics/Enums.h"
|
#include "Graphics/Enums.h"
|
||||||
|
#include "Graphics/Initializer.h"
|
||||||
|
|
||||||
using namespace Seele;
|
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() {}
|
FluidScene::~FluidScene() {}
|
||||||
|
|
||||||
@@ -12,37 +48,37 @@ void FluidScene::updateFluidData(uint32 entityID, const Component::Transform& tr
|
|||||||
auto& data = fluidDataMap[entityID];
|
auto& data = fluidDataMap[entityID];
|
||||||
uint64 totalCells = (uint64)grid.gridSize.x * grid.gridSize.y * grid.gridSize.z;
|
uint64 totalCells = (uint64)grid.gridSize.x * grid.gridSize.y * grid.gridSize.z;
|
||||||
uint64 bufferSize = totalCells * sizeof(float);
|
uint64 bufferSize = totalCells * sizeof(float);
|
||||||
Array<float> initialDensity(bufferSize / sizeof(float));
|
// Array<float> initialDensity(bufferSize / sizeof(float));
|
||||||
Array<float> initialVelocityX(bufferSize / sizeof(float));
|
// Array<float> initialVelocityX(bufferSize / sizeof(float));
|
||||||
Array<float> initialVelocityY(bufferSize / sizeof(float));
|
// Array<float> initialVelocityY(bufferSize / sizeof(float));
|
||||||
Array<float> initialVelocityZ(bufferSize / sizeof(float));
|
// Array<float> initialVelocityZ(bufferSize / sizeof(float));
|
||||||
Array<float> initialPhi(bufferSize / sizeof(float));
|
// Array<float> initialPhi(bufferSize / sizeof(float));
|
||||||
|
|
||||||
// Initialize level set to positive (outside) everywhere
|
// // Initialize level set to positive (outside) everywhere
|
||||||
float halfGridX = static_cast<float>(grid.gridSize.x) * 0.5f;
|
// float halfGridX = static_cast<float>(grid.gridSize.x) * 0.5f;
|
||||||
float halfGridY = static_cast<float>(grid.gridSize.y) * 0.5f;
|
// float halfGridY = static_cast<float>(grid.gridSize.y) * 0.5f;
|
||||||
float radius = static_cast<float>(grid.gridSize.x) * 0.2f;
|
// float radius = static_cast<float>(grid.gridSize.x) * 0.2f;
|
||||||
// Place sphere center in the lower portion of the grid
|
// // Place sphere center in the lower portion of the grid
|
||||||
float cx = halfGridX;
|
// float cx = halfGridX;
|
||||||
float cy = halfGridY;
|
// float cy = halfGridY;
|
||||||
float cz = static_cast<float>(grid.gridSize.z) * 0.3f;
|
// float cz = static_cast<float>(grid.gridSize.z) * 0.3f;
|
||||||
for (uint32 z = 1; z < grid.gridSize.z - 1; ++z) {
|
// for (uint32 z = 1; z < grid.gridSize.z - 1; ++z) {
|
||||||
for (uint32 y = 1; y < grid.gridSize.y - 1; ++y) {
|
// for (uint32 y = 1; y < grid.gridSize.y - 1; ++y) {
|
||||||
for (uint32 x = 1; x < grid.gridSize.x - 1; ++x) {
|
// for (uint32 x = 1; x < grid.gridSize.x - 1; ++x) {
|
||||||
uint32 idx = x + grid.gridSize.x * y + grid.gridSize.x * grid.gridSize.y * z;
|
// uint32 idx = x + grid.gridSize.x * y + grid.gridSize.x * grid.gridSize.y * z;
|
||||||
float dx = static_cast<float>(x) - cx;
|
// float dx = static_cast<float>(x) - cx;
|
||||||
float dy = static_cast<float>(y) - cy;
|
// float dy = static_cast<float>(y) - cy;
|
||||||
float dz = static_cast<float>(z) - cz;
|
// float dz = static_cast<float>(z) - cz;
|
||||||
float dist = std::sqrt(dx * dx + dy * dy + dz * dz);
|
// float dist = std::sqrt(dx * dx + dy * dy + dz * dz);
|
||||||
initialPhi[idx] = dist - radius;
|
// initialPhi[idx] = dist - radius;
|
||||||
if (dist < radius) {
|
// if (dist < radius) {
|
||||||
initialDensity[idx] = 1.0f;
|
// initialDensity[idx] = 1.0f;
|
||||||
// Give an initial upward velocity to kick the simulation
|
// // Give an initial upward velocity to kick the simulation
|
||||||
initialVelocityZ[idx] = 5.0f;
|
// initialVelocityZ[idx] = 5.0f;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
data.phiBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
data.phiBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||||
.sourceData =
|
.sourceData =
|
||||||
@@ -55,7 +91,7 @@ void FluidScene::updateFluidData(uint32 entityID, const Component::Transform& tr
|
|||||||
.sourceData =
|
.sourceData =
|
||||||
{
|
{
|
||||||
.size = bufferSize,
|
.size = bufferSize,
|
||||||
.data = (uint8*)initialPhi.data(),
|
// .data = (uint8*)initialPhi.data(),
|
||||||
},
|
},
|
||||||
.name = "Phi0Buffer",
|
.name = "Phi0Buffer",
|
||||||
});
|
});
|
||||||
@@ -70,7 +106,7 @@ void FluidScene::updateFluidData(uint32 entityID, const Component::Transform& tr
|
|||||||
.sourceData =
|
.sourceData =
|
||||||
{
|
{
|
||||||
.size = bufferSize,
|
.size = bufferSize,
|
||||||
.data = (uint8*)initialDensity.data(),
|
// .data = (uint8*)initialDensity.data(),
|
||||||
},
|
},
|
||||||
.name = "Density0Buffer",
|
.name = "Density0Buffer",
|
||||||
});
|
});
|
||||||
@@ -127,7 +163,7 @@ void FluidScene::updateFluidData(uint32 entityID, const Component::Transform& tr
|
|||||||
.sourceData =
|
.sourceData =
|
||||||
{
|
{
|
||||||
.size = bufferSize,
|
.size = bufferSize,
|
||||||
.data = (uint8*)initialVelocityX.data(),
|
// .data = (uint8*)initialVelocityX.data(),
|
||||||
},
|
},
|
||||||
.name = "VelocityX0Buffer",
|
.name = "VelocityX0Buffer",
|
||||||
});
|
});
|
||||||
@@ -135,7 +171,7 @@ void FluidScene::updateFluidData(uint32 entityID, const Component::Transform& tr
|
|||||||
.sourceData =
|
.sourceData =
|
||||||
{
|
{
|
||||||
.size = bufferSize,
|
.size = bufferSize,
|
||||||
.data = (uint8*)initialVelocityY.data(),
|
// .data = (uint8*)initialVelocityY.data(),
|
||||||
},
|
},
|
||||||
.name = "VelocityY0Buffer",
|
.name = "VelocityY0Buffer",
|
||||||
});
|
});
|
||||||
@@ -143,7 +179,7 @@ void FluidScene::updateFluidData(uint32 entityID, const Component::Transform& tr
|
|||||||
.sourceData =
|
.sourceData =
|
||||||
{
|
{
|
||||||
.size = bufferSize,
|
.size = bufferSize,
|
||||||
.data = (uint8*)initialVelocityZ.data(),
|
// .data = (uint8*)initialVelocityZ.data(),
|
||||||
},
|
},
|
||||||
.name = "VelocityZ0Buffer",
|
.name = "VelocityZ0Buffer",
|
||||||
});
|
});
|
||||||
@@ -157,17 +193,53 @@ void FluidScene::updateFluidData(uint32 entityID, const Component::Transform& tr
|
|||||||
.name = "IndexBuffer",
|
.name = "IndexBuffer",
|
||||||
});
|
});
|
||||||
data.surfaceCountBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
data.surfaceCountBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||||
.sourceData = {
|
.sourceData =
|
||||||
.size = 4 * sizeof(uint32),
|
{
|
||||||
},
|
.size = 4 * sizeof(uint32),
|
||||||
|
},
|
||||||
.usage = Gfx::SE_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
|
.usage = Gfx::SE_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
|
||||||
.name = "SurfaceCountBuffer",
|
.name = "SurfaceCountBuffer",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
auto& data = fluidDataMap[entityID];
|
auto& data = fluidDataMap[entityID];
|
||||||
|
data.paused = grid.paused;
|
||||||
data.transform = transform.transform;
|
data.transform = transform.transform;
|
||||||
data.cellSize = grid.cellSize;
|
data.dt = grid.dt;
|
||||||
data.viscosity = grid.viscosity;
|
data.viscosity = grid.viscosity;
|
||||||
data.diffusion = grid.diffusion;
|
data.diffusion = grid.diffusion;
|
||||||
data.gridSize = grid.gridSize;
|
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 "Containers/Map.h"
|
||||||
#include "Graphics/Buffer.h"
|
#include "Graphics/Buffer.h"
|
||||||
#include "Graphics/Graphics.h"
|
#include "Graphics/Graphics.h"
|
||||||
|
#include "Graphics/Resources.h"
|
||||||
#include "Graphics/Shader.h"
|
#include "Graphics/Shader.h"
|
||||||
#include "Math/Transform.h"
|
#include "Math/Transform.h"
|
||||||
#include "Math/Vector.h"
|
#include "Math/Vector.h"
|
||||||
@@ -17,10 +18,13 @@ class FluidScene {
|
|||||||
virtual ~FluidScene();
|
virtual ~FluidScene();
|
||||||
struct FluidData {
|
struct FluidData {
|
||||||
Math::Transform transform;
|
Math::Transform transform;
|
||||||
float cellSize;
|
bool paused;
|
||||||
float viscosity;
|
float viscosity;
|
||||||
float diffusion;
|
float diffusion;
|
||||||
|
float dt = 0.01f;
|
||||||
UVector gridSize;
|
UVector gridSize;
|
||||||
|
Vector gravity;
|
||||||
|
bool enableGravity;
|
||||||
Gfx::OShaderBuffer phiBuffer;
|
Gfx::OShaderBuffer phiBuffer;
|
||||||
Gfx::OShaderBuffer phi0Buffer;
|
Gfx::OShaderBuffer phi0Buffer;
|
||||||
Gfx::OShaderBuffer densityBuffer;
|
Gfx::OShaderBuffer densityBuffer;
|
||||||
@@ -49,7 +53,15 @@ class FluidScene {
|
|||||||
void updateFluidData(uint32 entityID, const Component::Transform& transform, const Component::FluidGrid& grid);
|
void updateFluidData(uint32 entityID, const Component::Transform& transform, const Component::FluidGrid& grid);
|
||||||
const Map<uint32, FluidData>& getFluidDataMap() const { return fluidDataMap; }
|
const Map<uint32, FluidData>& getFluidDataMap() const { return fluidDataMap; }
|
||||||
|
|
||||||
|
void addSource();
|
||||||
|
|
||||||
private:
|
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;
|
Gfx::PGraphics graphics;
|
||||||
Map<uint32, FluidData> fluidDataMap;
|
Map<uint32, FluidData> fluidDataMap;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "Scene.h"
|
#include "Scene.h"
|
||||||
#include "Graphics/Graphics.h"
|
#include "Graphics/Graphics.h"
|
||||||
|
#include "LightEnvironment.h"
|
||||||
|
#include "FluidScene.h"
|
||||||
|
|
||||||
using namespace Seele;
|
using namespace Seele;
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "MinimalEngine.h"
|
#include "MinimalEngine.h"
|
||||||
#include "Graphics/Graphics.h"
|
#include "Graphics/Graphics.h"
|
||||||
#include "LightEnvironment.h"
|
|
||||||
#include "Physics/PhysicsSystem.h"
|
#include "Physics/PhysicsSystem.h"
|
||||||
#include "FluidScene.h"
|
|
||||||
#include <entt/entt.hpp>
|
#include <entt/entt.hpp>
|
||||||
|
|
||||||
namespace Seele {
|
namespace Seele {
|
||||||
DECLARE_REF(Material)
|
DECLARE_REF(Material)
|
||||||
DECLARE_REF(Entity)
|
DECLARE_REF(Entity)
|
||||||
|
DECLARE_REF(FluidScene)
|
||||||
|
DECLARE_REF(LightEnvironment)
|
||||||
class Scene {
|
class Scene {
|
||||||
public:
|
public:
|
||||||
Scene(Gfx::PGraphics graphics);
|
Scene(Gfx::PGraphics graphics);
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#include "FluidUpdater.h"
|
#include "FluidUpdater.h"
|
||||||
|
#include "Graphics/DebugVertex.h"
|
||||||
|
#include "Scene/FluidScene.h"
|
||||||
|
|
||||||
using namespace Seele;
|
using namespace Seele;
|
||||||
using namespace Seele::System;
|
using namespace Seele::System;
|
||||||
@@ -10,4 +12,37 @@ FluidUpdater::~FluidUpdater() {}
|
|||||||
void FluidUpdater::update(entt::entity id, Component::FluidGrid &grid, Component::Transform &transform) {
|
void FluidUpdater::update(entt::entity id, Component::FluidGrid &grid, Component::Transform &transform) {
|
||||||
auto fluidScene = scene->getFluidScene();
|
auto fluidScene = scene->getFluidScene();
|
||||||
fluidScene->updateFluidData((uint32)id, transform, grid);
|
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 "LightGather.h"
|
||||||
|
#include "Scene/LightEnvironment.h"
|
||||||
|
|
||||||
using namespace Seele;
|
using namespace Seele;
|
||||||
using namespace Seele::System;
|
using namespace Seele::System;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "System/LightGather.h"
|
#include "System/LightGather.h"
|
||||||
#include "System/MeshUpdater.h"
|
#include "System/MeshUpdater.h"
|
||||||
#include "Window/Window.h"
|
#include "Window/Window.h"
|
||||||
|
#include "Scene/LightEnvironment.h"
|
||||||
|
|
||||||
using namespace Seele;
|
using namespace Seele;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user