From 0bd3ada39ebce5bbab6bdbb5b55fcecffa11f8af Mon Sep 17 00:00:00 2001 From: turanszkij Date: Mon, 7 May 2018 14:18:40 +0100 Subject: [PATCH] added emitter - sph properties --- Editor/EmitterWindow.cpp | 131 ++++++++++++++++++- Editor/EmitterWindow.h | 7 + WickedEngine/ShaderInterop_EmittedParticle.h | 14 +- WickedEngine/emittedparticle_nbodyCS.hlsl | 104 ++++++++------- WickedEngine/wiEmittedParticle.cpp | 26 +++- WickedEngine/wiEmittedParticle.h | 8 ++ 6 files changed, 237 insertions(+), 53 deletions(-) diff --git a/Editor/EmitterWindow.cpp b/Editor/EmitterWindow.cpp index 49a941aa8..aac73c1db 100644 --- a/Editor/EmitterWindow.cpp +++ b/Editor/EmitterWindow.cpp @@ -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(760, 800)); + emitterWindow->SetSize(XMFLOAT2(800, 1000)); emitterWindow->SetEnabled(false); GUI->AddWidget(emitterWindow); @@ -87,8 +87,22 @@ EmitterWindow::EmitterWindow(wiGUI* gui) : GUI(gui) emitterWindow->AddWidget(depthCollisionsCheckBox); + sphCheckBox = new wiCheckBox("SPH - FluidSim: "); + sphCheckBox->SetPos(XMFLOAT2(x + 400, y)); + sphCheckBox->OnClick([&](wiEventArgs args) { + auto emitter = GetEmitter(); + if (emitter != nullptr) + { + emitter->SPH_FLUIDSIMULATION = args.bValue; + } + }); + sphCheckBox->SetCheck(false); + sphCheckBox->SetTooltip("Enable particle collisions with each other. Simulate with Smooth Particle Hydrodynamics (SPH) solver."); + emitterWindow->AddWidget(sphCheckBox); + + debugCheckBox = new wiCheckBox("DEBUG: "); - debugCheckBox->SetPos(XMFLOAT2(x + 350, y)); + debugCheckBox->SetPos(XMFLOAT2(x + 500, y)); debugCheckBox->OnClick([&](wiEventArgs args) { auto emitter = GetEmitter(); if (emitter != nullptr) @@ -252,8 +266,95 @@ EmitterWindow::EmitterWindow(wiGUI* gui) : GUI(gui) emitMotionBlurSlider->SetTooltip("Set the motion blur amount for the particle system."); emitterWindow->AddWidget(emitMotionBlurSlider); + emitMassSlider = new wiSlider(0.1f, 100.0f, 1.0f, 100000, "Mass: "); + emitMassSlider->SetSize(XMFLOAT2(360, 30)); + emitMassSlider->SetPos(XMFLOAT2(x, y += step)); + emitMassSlider->OnSlide([&](wiEventArgs args) { + auto emitter = GetEmitter(); + if (emitter != nullptr) + { + emitter->mass = args.fValue; + } + }); + emitMassSlider->SetEnabled(false); + emitMassSlider->SetTooltip("Set the mass per particle."); + emitterWindow->AddWidget(emitMassSlider); + + + + //////////////// SPH //////////////////////////// + + y += step; + + sph_h_Slider = new wiSlider(0.1f, 100.0f, 1.0f, 100000, "SPH Smoothing Radius (h): "); + sph_h_Slider->SetSize(XMFLOAT2(360, 30)); + sph_h_Slider->SetPos(XMFLOAT2(x, y += step)); + sph_h_Slider->OnSlide([&](wiEventArgs args) { + auto emitter = GetEmitter(); + if (emitter != nullptr) + { + emitter->SPH_h = args.fValue; + } + }); + sph_h_Slider->SetEnabled(false); + sph_h_Slider->SetTooltip("Set the SPH parameter: smoothing radius"); + emitterWindow->AddWidget(sph_h_Slider); + + sph_K_Slider = new wiSlider(0.1f, 100.0f, 1.0f, 100000, "SPH Pressure Constant (K): "); + sph_K_Slider->SetSize(XMFLOAT2(360, 30)); + sph_K_Slider->SetPos(XMFLOAT2(x, y += step)); + sph_K_Slider->OnSlide([&](wiEventArgs args) { + auto emitter = GetEmitter(); + if (emitter != nullptr) + { + emitter->SPH_K = args.fValue; + } + }); + sph_K_Slider->SetEnabled(false); + sph_K_Slider->SetTooltip("Set the SPH parameter: pressure constant"); + emitterWindow->AddWidget(sph_K_Slider); + + sph_p0_Slider = new wiSlider(0.1f, 100.0f, 1.0f, 100000, "SPH Reference Density (p0): "); + sph_p0_Slider->SetSize(XMFLOAT2(360, 30)); + sph_p0_Slider->SetPos(XMFLOAT2(x, y += step)); + sph_p0_Slider->OnSlide([&](wiEventArgs args) { + auto emitter = GetEmitter(); + if (emitter != nullptr) + { + emitter->SPH_p0 = args.fValue; + } + }); + sph_p0_Slider->SetEnabled(false); + sph_p0_Slider->SetTooltip("Set the SPH parameter: reference density"); + emitterWindow->AddWidget(sph_p0_Slider); + + sph_e_Slider = new wiSlider(0.1f, 100.0f, 1.0f, 100000, "SPH Viscosity (e): "); + sph_e_Slider->SetSize(XMFLOAT2(360, 30)); + sph_e_Slider->SetPos(XMFLOAT2(x, y += step)); + sph_e_Slider->OnSlide([&](wiEventArgs args) { + auto emitter = GetEmitter(); + if (emitter != nullptr) + { + emitter->SPH_e = args.fValue; + } + }); + sph_e_Slider->SetEnabled(false); + sph_e_Slider->SetTooltip("Set the SPH parameter: viscosity constant"); + emitterWindow->AddWidget(sph_e_Slider); + + + + + + + + + ////// UTIL ///////////////// + + y += step; + materialSelectButton = new wiButton("Select Material"); materialSelectButton->SetPos(XMFLOAT2(x, y += step)); materialSelectButton->SetSize(XMFLOAT2(150, 30)); @@ -271,6 +372,26 @@ EmitterWindow::EmitterWindow(wiGUI* gui) : GUI(gui) emitterWindow->AddWidget(materialSelectButton); + + restartButton = new wiButton("Restart Emitter"); + restartButton->SetPos(XMFLOAT2(x + 200, y)); + restartButton->SetSize(XMFLOAT2(150, 30)); + restartButton->OnClick([&](wiEventArgs args) { + if (materialWnd != nullptr) + { + auto emitter = GetEmitter(); + if (emitter != nullptr) + { + emitter->Restart(); + } + } + }); + restartButton->SetTooltip("Restart particle system emitter"); + emitterWindow->AddWidget(restartButton); + + + + emitterWindow->Translate(XMFLOAT3(200, 50, 0)); emitterWindow->SetVisible(false); @@ -325,6 +446,12 @@ void EmitterWindow::SetObject(Object* obj) emitRandomnessSlider->SetValue(emitter->random_factor); emitLifeRandomnessSlider->SetValue(emitter->random_life); emitMotionBlurSlider->SetValue(emitter->motionBlurAmount); + emitMassSlider->SetValue(emitter->mass); + + sph_h_Slider->SetValue(emitter->SPH_h); + sph_K_Slider->SetValue(emitter->SPH_K); + sph_p0_Slider->SetValue(emitter->SPH_p0); + sph_e_Slider->SetValue(emitter->SPH_e); } emitterWindow->SetEnabled(true); diff --git a/Editor/EmitterWindow.h b/Editor/EmitterWindow.h index 3afe0279c..9c185be47 100644 --- a/Editor/EmitterWindow.h +++ b/Editor/EmitterWindow.h @@ -37,6 +37,7 @@ public: wiSlider* maxParticlesSlider; wiCheckBox* sortCheckBox; wiCheckBox* depthCollisionsCheckBox; + wiCheckBox* sphCheckBox; wiCheckBox* debugCheckBox; wiSlider* emitCountSlider; wiSlider* emitSizeSlider; @@ -47,7 +48,13 @@ public: wiSlider* emitRandomnessSlider; wiSlider* emitLifeRandomnessSlider; wiSlider* emitMotionBlurSlider; + wiSlider* emitMassSlider; + wiSlider* sph_h_Slider; + wiSlider* sph_K_Slider; + wiSlider* sph_p0_Slider; + wiSlider* sph_e_Slider; wiButton* materialSelectButton; + wiButton* restartButton; }; diff --git a/WickedEngine/ShaderInterop_EmittedParticle.h b/WickedEngine/ShaderInterop_EmittedParticle.h index d9d78f069..3fa15cd82 100644 --- a/WickedEngine/ShaderInterop_EmittedParticle.h +++ b/WickedEngine/ShaderInterop_EmittedParticle.h @@ -41,9 +41,21 @@ CBUFFER(EmittedParticleCB, CBSLOT_OTHER_EMITTEDPARTICLE) float xParticleLifeSpan; float xParticleLifeSpanRandomness; + float xParticleMass; float xParticleMotionBlurAmount; float xEmitterOpacity; - float2 xPadding_EmitterCB; + float xPadding0_EmitterCB; + + float xSPH_h; // 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_e; // viscosity constant + }; CBUFFER(SortConstants, 0) diff --git a/WickedEngine/emittedparticle_nbodyCS.hlsl b/WickedEngine/emittedparticle_nbodyCS.hlsl index 24fcd34e2..82e699d3e 100644 --- a/WickedEngine/emittedparticle_nbodyCS.hlsl +++ b/WickedEngine/emittedparticle_nbodyCS.hlsl @@ -34,7 +34,7 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, ui LDSParticles[groupIndex].position = particleA.position; LDSParticles[groupIndex].size = particleSizeA; LDSParticles[groupIndex].v = particleA.velocity; - LDSParticles[groupIndex].m = 1; + LDSParticles[groupIndex].m = xParticleMass; LDSParticles[groupIndex].p = 0; LDSParticles[groupIndex].P = 0; @@ -49,12 +49,18 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, ui LDSParticle particleA = LDSParticles[particleIndexA]; - // Compute density field: + // SPH params: + 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 - const float h = 1.0f; // smoothing radius - const float h2 = h*h; - const float h3 = h2 * h; - const float h9 = h3 * h3; + + // Compute density field: uint i; @@ -68,10 +74,10 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, ui float3 diff = particleA.position - particleB.position; float r2 = dot(diff, diff); // distance squared - float range = particleA.size + particleB.size; // range of affection - float range2 = range * range; // range squared + //float range = particleA.size + particleB.size; // range of affection + //float range2 = range * range; // range squared - if (r2 < range2) + if (r2 < h2) { float W = (315.0f / (64.0f * PI * h9)) * pow(h2 - r2, 3); // poly6 smoothing kernel @@ -81,10 +87,15 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, ui } } + int asd = 0; + if (particleA.p > p0) asd = 1; + if (particleA.p < p0) asd = -1; + + // Can't be lower than reference density to avoid negative pressure! + //particleA.p = max(p0, particleA.p); + // Compute particle pressure: - const float K = 20; // pressure constant - const float p0 = 20; // reference density - particleA.P = max(p0, K * (particleA.p - p0)); + particleA.P = K * (max(p0, particleA.p) - p0); // Store the results: LDSParticles[particleIndexA].p = particleA.p; @@ -101,7 +112,6 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, ui // Compute acceleration: float3 a = 0; // pressure force float3 av = 0; // viscosity force - const float e = 0.018f; // viscosity constant for (i = 0; i < LDSParticleCount; ++i) { @@ -114,33 +124,31 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, ui float r2 = dot(diff, diff); // distance squared float r = sqrt(r2); - float range = particleA.size + particleB.size; // range of affection + //float range = particleA.size + particleB.size; // range of affection - if (r < range) + if (r < h) { float3 rNorm = normalize(diff); - float W = (-45 / (PI * pow(h, 6))) * pow(h - r, 2); // spiky kernel smoothing function + float W = (-45 / (PI * h6)) * pow(h - r, 2); // spiky kernel smoothing function - a += -(particleB.m / particleA.m) * ((particleA.P + particleB.P) / (2 * particleA.p * particleB.p)) * W * rNorm; + a += (particleB.m / particleA.m) * ((particleA.P + particleB.P) / (2 * particleA.p * particleB.p)) * W * rNorm; float r3 = r2 * r; - float h2 = h * h; - float h3 = h2 * h; W = -(r3 / (2 * h3)) + (r2 / h2) + (h / (2 * r)) - 1; - av += e * (particleB.m / particleA.m) * (1.0f / particleB.p) * (particleB.v - particleA.v) * W * rNorm; + av += (particleB.m / particleA.m) * (1.0f / particleB.p) * (particleB.v - particleA.v) * W * rNorm; } } } - //a *= -1; - - //av *= e; + a *= -1; + av *= e; float3 force = a + av; const float dt = g_xFrame_DeltaTime; particleA.v += dt * force / particleA.p; + particleA.position += dt * particleA.v; } @@ -152,28 +160,28 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, ui particleA.v.y *= -elastic; } - //// box collision: - //float extent = 4; - //if (particleA.position.x + particleA.size > extent) - //{ - // particleA.position.x = extent - particleA.size; - // particleA.v.x *= -elastic; - //} - //if (particleA.position.x - particleA.size < -extent) - //{ - // particleA.position.x = -extent + particleA.size; - // particleA.v.x *= -elastic; - //} - //if (particleA.position.z + particleA.size > extent) - //{ - // particleA.position.z = extent - particleA.size; - // particleA.v.z *= -elastic; - //} - //if (particleA.position.z - particleA.size < -extent) - //{ - // particleA.position.z = -extent + particleA.size; - // particleA.v.z *= -elastic; - //} + // box collision: + float extent = 2; + if (particleA.position.x + particleA.size > extent) + { + particleA.position.x = extent - particleA.size; + particleA.v.x *= -elastic; + } + if (particleA.position.x - particleA.size < -extent) + { + particleA.position.x = -extent + particleA.size; + particleA.v.x *= -elastic; + } + if (particleA.position.z + particleA.size > extent) + { + particleA.position.z = extent - particleA.size; + particleA.v.z *= -elastic; + } + if (particleA.position.z - particleA.size < -extent) + { + particleA.position.z = -extent + particleA.size; + particleA.v.z *= -elastic; + } particleA.v *= 0.99f; @@ -189,10 +197,14 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, ui particleBuffer[writeIndex].color_mirror = 0x00FFFFFF; //particleBuffer[writeIndex].color_mirror |= ((uint)particleA.p) & 0xFF; - if (particleA.p > 0) + if (asd > 0) { particleBuffer[writeIndex].color_mirror = 0xFF; } + if (asd < 0) + { + particleBuffer[writeIndex].color_mirror = 0xFF00; + } } diff --git a/WickedEngine/wiEmittedParticle.cpp b/WickedEngine/wiEmittedParticle.cpp index abb5e7a57..adf39b768 100644 --- a/WickedEngine/wiEmittedParticle.cpp +++ b/WickedEngine/wiEmittedParticle.cpp @@ -279,6 +279,10 @@ void wiEmittedParticle::Burst(float num) { emit += num; } +void wiEmittedParticle::Restart() +{ + buffersUpToDate = false; +} void wiEmittedParticle::UpdateRenderData(GRAPHICSTHREAD threadID) @@ -304,6 +308,17 @@ void wiEmittedParticle::UpdateRenderData(GRAPHICSTHREAD threadID) cb.xParticleRotation = rotation * XM_PI * 60; cb.xParticleColor = wiMath::CompressColor(XMFLOAT4(material->baseColor.x, material->baseColor.y, material->baseColor.z, 1)); cb.xEmitterOpacity = material->alpha; + cb.xParticleMass = mass; + + // SPH: + cb.xSPH_h = 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; + cb.xSPH_K = SPH_K; + cb.xSPH_p0 = SPH_p0; + cb.xSPH_e = SPH_e; device->UpdateBuffer(constantBuffer, &cb, threadID); device->BindConstantBuffer(CS, constantBuffer, CB_GETBINDSLOT(EmittedParticleCB), threadID); @@ -343,10 +358,13 @@ void wiEmittedParticle::UpdateRenderData(GRAPHICSTHREAD threadID) device->DispatchIndirect(indirectBuffers, ARGUMENTBUFFER_OFFSET_DISPATCHEMIT, threadID); device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID); - // perform N-body collision response simulation: - device->BindComputePSO(&CPSO_nbody, threadID); - device->DispatchIndirect(indirectBuffers, ARGUMENTBUFFER_OFFSET_DISPATCHSIMULATION, threadID); - device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID); + if (SPH_FLUIDSIMULATION) + { + // perform N-body collision response simulation: + device->BindComputePSO(&CPSO_nbody, threadID); + device->DispatchIndirect(indirectBuffers, ARGUMENTBUFFER_OFFSET_DISPATCHSIMULATION, threadID); + device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID); + } // update CURRENT alive list, write NEW alive list if (SORTING) diff --git a/WickedEngine/wiEmittedParticle.h b/WickedEngine/wiEmittedParticle.h index 89eae494d..7cda3eb75 100644 --- a/WickedEngine/wiEmittedParticle.h +++ b/WickedEngine/wiEmittedParticle.h @@ -69,6 +69,7 @@ public: void Update(float dt); void Burst(float num); + void Restart(); void UpdateRenderData(GRAPHICSTHREAD threadID); @@ -80,6 +81,7 @@ public: bool SORTING = false; bool DEPTHCOLLISIONS = false; + bool SPH_FLUIDSIMULATION = false; PARTICLESHADERTYPE shaderType = SOFT; @@ -92,6 +94,12 @@ public: float count,life,random_life; float scaleX,scaleY,rotation; float motionBlurAmount; + float mass = 1.0f; + + float SPH_h = 0.2f; // smoothing radius + float SPH_K = 20.0f; // pressure constant + float SPH_p0 = 20.0f; // reference density + float SPH_e = 0.018f; // viscosity constant void SetMaxParticleCount(uint32_t value); uint32_t GetMaxParticleCount() const { return MAX_PARTICLES; }