Hi,
I've been trying to get a basic fluid simulation up and running but I've run into a dead end: for several days now I've been trying to find where I've gone wrong and I'm still looking. I started with a 3D Eulerian grid based simulation but debugging that was a nightmare so I've now coded up a 2D version and I can see the issue clearer now (at least I think so). The simulation seems to run fine for the first couple of frames but after that it just seems to stop: I mean the velocity doesn't spread through the fluid (you can see small changes within the area that was initially affected). From what I can tell, the divergence I calculate to find pressure goes to 0 after a few frames (~10). Thus the pressure will also be 0 and then the projection in the end just copies previous frames velocity.
Here are a couple of screenshots of different properties: (not scale-corrected colors, e.g. there are negative values for velocity)
velocity: http://postimg.org/image/th0fraz5d/
divergence: http://postimg.org/image/am7wseu6r/
pressure is just a mirrored image of divergence (at least so it looks like, has a bigger area and disappears a bit slower though)
color property (or "dye" if you will): http://postimg.org/image/yun01ufzd/
The color/velocity values were written using a simple gaussian splat, with white as color value and (10.0f, 10.0f, 0.0f) as velocity values. Thus the direction seems about correct to me.
Since I'm doing the simulation on the GPU, there's a lot of code involved with ping-ponging render targets etc but none of my debugging tools show any issues with the pipeline and all data buffers seem to contain the correct data at each step. So, I'm left wondering if my maths is correct: I've consulted both GPU gems books that had articles about this and checked my versions against theirs and I simply can't find any differences, yet the simulation isn't working as intended.
For now, I'll just post my advection for color/velocity and divergence routines as (to me) it seems to be going wrong already at one of these steps.
input.position is the pixel position SV_Position. Also, helper func used in both cases (texDim is simulation grid width/height which currently matches the viewport):
float2 PositionToTexCoord(float2 position) {
return float2(position.x / texDim.x, position.y / texDim.y);
}
Advection:
float4 PSMain(PSInput input) : SV_TARGET {
float2 center = PositionToTexCoord(input.position.xy);
float2 pos = input.position.xy - dt * velocity.Sample(pointSampler, center).rg;
float2 samplingPoint = PositionToTexCoord(pos);
return qtyToAdvect.Sample(linearSampler, samplingPoint);
}
float PSMain(PSInput input) : SV_TARGET {
float2 left = PositionToTexCoord(input.position.xy - float2(1.0f, 0.0f));
float2 right = PositionToTexCoord(input.position.xy + float2(1.0f, 0.0f));
float2 bottom = PositionToTexCoord(input.position.xy + float2(0.0f, 1.0f));
float2 top = PositionToTexCoord(input.position.xy - float2(0.0f, 1.0f));
float4 l = velocity.Sample(pointSampler, left);
float4 r = velocity.Sample(pointSampler, right);
float4 b = velocity.Sample(pointSampler, bottom);
float4 t = velocity.Sample(pointSampler, top);
float div = 0.5f * ((r.x - l.x) + (t.y - b.y));
return div;
}