emitter updates, optimize fluid simulator

This commit is contained in:
turanszkij
2018-05-19 14:27:06 +01:00
parent 498c60df26
commit c967df400b
11 changed files with 119 additions and 71 deletions
+18 -1
View File
@@ -18,7 +18,7 @@ EmitterWindow::EmitterWindow(wiGUI* gui) : GUI(gui)
float screenH = (float)wiRenderer::GetDevice()->GetScreenHeight();
emitterWindow = new wiWindow(GUI, "Emitter Window");
emitterWindow->SetSize(XMFLOAT2(800, 1024));
emitterWindow->SetSize(XMFLOAT2(800, 1100));
emitterWindow->SetEnabled(false);
GUI->AddWidget(emitterWindow);
@@ -296,6 +296,22 @@ EmitterWindow::EmitterWindow(wiGUI* gui) : GUI(gui)
timestepSlider = new wiSlider(-1, 0.016f, -1, 100000, "Timestep: ");
timestepSlider->SetSize(XMFLOAT2(360, 30));
timestepSlider->SetPos(XMFLOAT2(x, y += step*2));
timestepSlider->OnSlide([&](wiEventArgs args) {
auto emitter = GetEmitter();
if (emitter != nullptr)
{
emitter->FIXED_TIMESTEP = args.fValue;
}
});
timestepSlider->SetEnabled(false);
timestepSlider->SetTooltip("Adjust timestep for emitter simulation. -1 means variable timestep, positive means fixed timestep.");
emitterWindow->AddWidget(timestepSlider);
//////////////// SPH ////////////////////////////
@@ -463,6 +479,7 @@ void EmitterWindow::SetObject(Object* obj)
emitLifeRandomnessSlider->SetValue(emitter->random_life);
emitMotionBlurSlider->SetValue(emitter->motionBlurAmount);
emitMassSlider->SetValue(emitter->mass);
timestepSlider->SetValue(emitter->FIXED_TIMESTEP);
sph_h_Slider->SetValue(emitter->SPH_h);
sph_K_Slider->SetValue(emitter->SPH_K);
+1
View File
@@ -50,6 +50,7 @@ public:
wiSlider* emitLifeRandomnessSlider;
wiSlider* emitMotionBlurSlider;
wiSlider* emitMassSlider;
wiSlider* timestepSlider;
wiSlider* sph_h_Slider;
wiSlider* sph_K_Slider;
wiSlider* sph_p0_Slider;
+1
View File
@@ -1,5 +1,6 @@
This file contains changelog of wiArchive versions
18: serialized emitter properties: sph properties, fixed timestep
17: serialized light scattering property
16: environment probes are now serialized into Model
15: removed redundant matrix store from hair paticle serializator
+14 -13
View File
@@ -6,9 +6,9 @@
struct Particle
{
float3 position;
float rotationalVelocity;
float3 force;
float mass;
float3 force;
float rotationalVelocity;
float3 velocity;
float maxLife;
float life;
@@ -52,19 +52,20 @@ CBUFFER(EmittedParticleCB, CBSLOT_OTHER_EMITTEDPARTICLE)
float xEmitterOpacity;
uint xEmitterMaxParticleCount;
float xSPH_h; // smoothing radius
float xSPH_h_rcp; // 1.0f / smoothing radius
float xSPH_h2; // smoothing radius ^ 2
float xSPH_h3; // smoothing radius ^ 3
float xSPH_h; // smoothing radius
float xSPH_h_rcp; // 1.0f / smoothing radius
float xSPH_h2; // smoothing radius ^ 2
float xSPH_h3; // smoothing radius ^ 3
float xSPH_h6; // smoothing radius ^ 6
float xSPH_h9; // smoothing radius ^ 9
float xSPH_K; // pressure constant
float xSPH_p0; // reference density
float xSPH_poly6_constant; // precomputed Poly6 kernel constant term
float xSPH_spiky_constant; // precomputed Spiky kernel function constaant term
float xSPH_K; // pressure constant
float xSPH_p0; // reference density
float xSPH_e; // viscosity constant
uint xSPH_ENABLED;
float2 __padding;
float xSPH_e; // viscosity constant
uint xSPH_ENABLED; // is SPH enabled?
float xEmitterFixedTimestep; // we can force a fixed timestep (>0) onto the simulation to avoid blowing up
float __padding;
};
+2 -2
View File
@@ -49,8 +49,8 @@ void main(uint3 DTid : SV_DispatchThreadID, uint Gid : SV_GroupIndex)
if (DTid.x < aliveCount)
{
//const float dt = g_xFrame_DeltaTime;
const float dt = 0.016f; // fixed time step, otherwise simulation can just blow up
// simulation can be either fixed or variable timestep:
const float dt = xEmitterFixedTimestep >= 0 ? xEmitterFixedTimestep : g_xFrame_DeltaTime;
uint particleIndex = aliveBuffer_CURRENT[DTid.x];
Particle particle = particleBuffer[particleIndex];
+32 -33
View File
@@ -9,7 +9,10 @@ STRUCTUREDBUFFER(cellOffsetBuffer, uint, 4);
RWSTRUCTUREDBUFFER(densityBuffer, float, 0);
#ifndef SPH_USE_ACCELERATION_GRID
// grid structure is not a good fit to exploit shared memory because one threadgroup can load from different initial cells :(
groupshared float4 positions_masses[THREADCOUNT_SIMULATION];
#endif // SPH_USE_ACCELERATION_GRID
[numthreads(THREADCOUNT_SIMULATION, 1, 1)]
void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, uint3 Gid : SV_GroupID )
@@ -18,8 +21,6 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, ui
const float h = xSPH_h; // smoothing radius
const float h2 = xSPH_h2; // smoothing radius ^ 2
const float h3 = xSPH_h3; // smoothing radius ^ 3
const float h6 = xSPH_h6; // smoothing radius ^ 6
const float h9 = xSPH_h9; // smoothing radius ^ 9
const float K = xSPH_K; // pressure constant
const float p0 = xSPH_p0; // reference density
const float e = xSPH_e; // viscosity constant
@@ -27,17 +28,17 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, ui
uint aliveCount = counterBuffer.Load(PARTICLECOUNTER_OFFSET_ALIVECOUNT);
uint particleIndexA;
Particle particleA;
float3 positionA;
if (DTid.x < aliveCount)
{
particleIndexA = aliveBuffer_CURRENT[DTid.x];
particleA = particleBuffer[particleIndexA];
positionA = particleBuffer[particleIndexA].position;
}
else
{
particleIndexA = 0xFFFFFFFF;
particleA = (Particle)0;
positionA = 0;
}
@@ -48,10 +49,10 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, ui
#ifdef SPH_USE_ACCELERATION_GRID
// Grid cell is of size [SPH smoothing radius], so position is refitted into that
float3 remappedPos = particleA.position * xSPH_h_rcp;
int3 cellIndex = floor(remappedPos);
const float3 remappedPos = positionA * xSPH_h_rcp;
const int3 cellIndex = floor(remappedPos);
// iterate through all [27] neighbor cells:
[loop]
for (int i = -1; i <= 1; ++i)
{
@@ -61,39 +62,38 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, ui
[loop]
for (int k = -1; k <= 1; ++k)
{
// hashed cell index is retrieved:
const int3 neighborIndex = cellIndex + int3(i, j, k);
const uint flatNeighborIndex = SPH_GridHash(neighborIndex);
// look up the offset into particle list from neighbor cell:
uint neighborIterator = cellOffsetBuffer[flatNeighborIndex];
// iterate through neighbor cell particles (if iterator offset is valid):
[loop]
while (neighborIterator != 0xFFFFFFFF && neighborIterator < aliveCount)
{
//if (neighborIterator != DTid.x) // actually, without this check, the whole thing is just more stable
uint particleIndexB = aliveBuffer_CURRENT[neighborIterator];
if ((uint)cellIndexBuffer[particleIndexB] != flatNeighborIndex)
{
uint particleIndexB = aliveBuffer_CURRENT[neighborIterator];
if ((uint)cellIndexBuffer[particleIndexB] != flatNeighborIndex)
{
break;
}
// SPH Density evaluation:
{
Particle particleB = particleBuffer[particleIndexB];
float3 diff = particleA.position - particleB.position;
float r2 = dot(diff, diff); // distance squared
if (r2 < h2)
{
float W = (315.0f / (64.0f * PI * h9)) * pow(h2 - r2, 3); // poly6 smoothing kernel
density += particleB.mass * W;
}
}
// here means we stepped out of the neighbor cell list!
break;
}
// SPH Density evaluation:
{
Particle particleB = particleBuffer[particleIndexB];
float3 diff = positionA - particleB.position;
float r2 = dot(diff, diff); // distance squared
if (r2 < h2)
{
float W = xSPH_poly6_constant * pow(h2 - r2, 3); // poly6 smoothing kernel
density += particleB.mass * W;
}
}
neighborIterator++;
}
@@ -130,12 +130,12 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, ui
{
float3 positionB = positions_masses[i].xyz;
float3 diff = particleA.position - positionB;
float3 diff = positionA - positionB;
float r2 = dot(diff, diff); // distance squared
if (r2 < h2)
{
float W = (315.0f / (64.0f * PI * h9)) * pow(h2 - r2, 3); // poly6 smoothing kernel
float W = xSPH_poly6_constant * pow(h2 - r2, 3); // poly6 smoothing kernel
float mass = positions_masses[i].w;
@@ -160,7 +160,6 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, ui
// Store the results:
densityBuffer[particleIndexA] = density;
}
+22 -18
View File
@@ -11,9 +11,12 @@ STRUCTUREDBUFFER(cellOffsetBuffer, uint, 4);
RWSTRUCTUREDBUFFER(particleBuffer, Particle, 0);
#ifndef SPH_USE_ACCELERATION_GRID
// grid structure is not a good fit to exploit shared memory because one threadgroup can load from different initial cells :(
groupshared float4 positions_densities[THREADCOUNT_SIMULATION];
groupshared float4 velocities_pressures[THREADCOUNT_SIMULATION];
groupshared float masses[THREADCOUNT_SIMULATION];
#endif // SPH_USE_ACCELERATION_GRID
[numthreads(THREADCOUNT_SIMULATION, 1, 1)]
void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, uint3 Gid : SV_GroupID )
@@ -22,8 +25,6 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, ui
const float h = xSPH_h; // smoothing radius
const float h2 = xSPH_h2; // smoothing radius ^ 2
const float h3 = xSPH_h3; // smoothing radius ^ 3
const float h6 = xSPH_h6; // smoothing radius ^ 6
const float h9 = xSPH_h9; // smoothing radius ^ 9
const float K = xSPH_K; // pressure constant
const float p0 = xSPH_p0; // reference density
const float e = xSPH_e; // viscosity constant
@@ -60,10 +61,10 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, ui
#ifdef SPH_USE_ACCELERATION_GRID
// Grid cell is of size [SPH smoothing radius], so position is refitted into that
float3 remappedPos = particleA.position * xSPH_h_rcp;
int3 cellIndex = floor(remappedPos);
const float3 remappedPos = particleA.position * xSPH_h_rcp;
const int3 cellIndex = floor(remappedPos);
// iterate through all [27] neighbor cells:
[loop]
for (int i = -1; i <= 1; ++i)
{
@@ -73,12 +74,14 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, ui
[loop]
for (int k = -1; k <= 1; ++k)
{
// hashed cell index is retrieved:
const int3 neighborIndex = cellIndex + int3(i, j, k);
const uint flatNeighborIndex = SPH_GridHash(neighborIndex);
// look up the offset into particle list from neighbor cell:
uint neighborIterator = cellOffsetBuffer[flatNeighborIndex];
// iterate through neighbor cell particles (if iterator offset is valid):
[loop]
while (neighborIterator != 0xFFFFFFFF && neighborIterator < aliveCount)
{
@@ -87,27 +90,28 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, ui
uint particleIndexB = aliveBuffer_CURRENT[neighborIterator];
if ((uint)cellIndexBuffer[particleIndexB] != flatNeighborIndex)
{
// here means we stepped out of the neighbor cell list!
break;
}
// SPH Force evaluation:
{
float3 positionB = particleBuffer[particleIndexB].position.xyz;
const float3 positionB = particleBuffer[particleIndexB].position.xyz;
float3 diff = particleA.position - positionB;
float r2 = dot(diff, diff); // distance squared
float r = sqrt(r2);
const float3 diff = particleA.position - positionB;
const float r2 = dot(diff, diff); // distance squared
const float r = sqrt(r2);
if (r < h)
{
float3 velocityB = particleBuffer[particleIndexB].velocity.xyz;
float densityB = densityBuffer[particleIndexB];
float pressureB = K * (densityB - p0);
const float3 velocityB = particleBuffer[particleIndexB].velocity.xyz;
const float densityB = densityBuffer[particleIndexB];
const float pressureB = K * (densityB - p0);
float3 rNorm = normalize(diff);
float W = (-45 / (PI * h6)) * pow(h - r, 2); // spiky kernel smoothing function
const float3 rNorm = normalize(diff);
float W = xSPH_spiky_constant * pow(h - r, 2); // spiky kernel smoothing function
float mass = particleBuffer[particleIndexB].mass / particleA.mass;
const float mass = particleBuffer[particleIndexB].mass / particleA.mass;
f_a += mass * ((pressureA + pressureB) / (2 * densityA * densityB)) * W * rNorm;
@@ -173,7 +177,7 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, ui
float pressureB = velocities_pressures[i].w;
float3 rNorm = normalize(diff);
float W = (-45 / (PI * h6)) * pow(h - r, 2); // spiky kernel smoothing function
float W = xSPH_spiky_constant * pow(h - r, 2); // spiky kernel smoothing function
float mass = masses[i] / particleA.mass;
@@ -211,7 +215,7 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, ui
#ifdef DEBUG_PRESSURE
// debug pressure:
float3 color = lerp(float3(1, 1, 1), float3(1, 0, 0), saturate(abs(pressureA - p0) * 0.01f)) * 255;
float3 color = lerp(float3(1, 1, 1), float3(1, 0, 0), saturate(pressureA * 0.005f)) * 255;
uint uColor = 0;
uColor |= (uint)color.r << 0;
uColor |= (uint)color.g << 8;
+1 -1
View File
@@ -7,7 +7,7 @@
using namespace std;
// this should always be only INCREMENTED and only if a new serialization is implemeted somewhere!
uint64_t __archiveVersion = 17;
uint64_t __archiveVersion = 18;
// this is the version number of which below the archive is not compatible with the current version
uint64_t __archiveVersionBarrier = 1;
+26 -2
View File
@@ -346,14 +346,17 @@ void wiEmittedParticle::UpdateRenderData(GRAPHICSTHREAD threadID)
cb.xEmitterOpacity = material->alpha;
cb.xParticleMass = mass;
cb.xEmitterMaxParticleCount = MAX_PARTICLES;
cb.xEmitterFixedTimestep = FIXED_TIMESTEP;
// SPH:
cb.xSPH_h = SPH_h;
cb.xSPH_h_rcp = 1.0f / SPH_h;
cb.xSPH_h2 = SPH_h * SPH_h;
cb.xSPH_h3 = cb.xSPH_h2 * SPH_h;
cb.xSPH_h6 = cb.xSPH_h2 * cb.xSPH_h2 * cb.xSPH_h2;
cb.xSPH_h9 = cb.xSPH_h3 * cb.xSPH_h3;
const float h6 = cb.xSPH_h2 * cb.xSPH_h2 * cb.xSPH_h2;
const float h9 = cb.xSPH_h3 * cb.xSPH_h3;
cb.xSPH_poly6_constant = (315.0f / (64.0f * XM_PI * h9));
cb.xSPH_spiky_constant = (-45 / (XM_PI * h6));
cb.xSPH_K = SPH_K;
cb.xSPH_p0 = SPH_p0;
cb.xSPH_e = SPH_e;
@@ -938,6 +941,16 @@ void wiEmittedParticle::Serialize(wiArchive& archive)
archive >> tmp;
shaderType = (PARTICLESHADERTYPE)tmp;
}
if (archive.GetVersion() >= 18)
{
archive >> mass;
archive >> FIXED_TIMESTEP;
archive >> SPH_FLUIDSIMULATION;
archive >> SPH_h;
archive >> SPH_K;
archive >> SPH_p0;
archive >> SPH_e;
}
}
else
@@ -968,5 +981,16 @@ void wiEmittedParticle::Serialize(wiArchive& archive)
{
archive << (int)shaderType;
}
if (archive.GetVersion() >= 18)
{
archive << mass;
archive << FIXED_TIMESTEP;
archive << SPH_FLUIDSIMULATION;
archive << SPH_h;
archive << SPH_K;
archive << SPH_p0;
archive << SPH_e;
}
}
}
+1
View File
@@ -85,6 +85,7 @@ public:
bool SORTING = false;
bool DEPTHCOLLISIONS = false;
bool SPH_FLUIDSIMULATION = false;
float FIXED_TIMESTEP = -1.0f; // -1 : variable timestep; >=0 : fixed timestep
PARTICLESHADERTYPE shaderType = SOFT;
+1 -1
View File
@@ -9,7 +9,7 @@ namespace wiVersion
// minor features, major updates
const int minor = 17;
// minor bug fixes, alterations, refactors, updates
const int revision = 21;
const int revision = 22;
long GetVersion()