diff --git a/Editor/EmitterWindow.cpp b/Editor/EmitterWindow.cpp index aac73c1db..c024551fc 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(800, 1000)); + emitterWindow->SetSize(XMFLOAT2(800, 1024)); emitterWindow->SetEnabled(false); GUI->AddWidget(emitterWindow); @@ -101,8 +101,22 @@ EmitterWindow::EmitterWindow(wiGUI* gui) : GUI(gui) emitterWindow->AddWidget(sphCheckBox); + pauseCheckBox = new wiCheckBox("PAUSE: "); + pauseCheckBox->SetPos(XMFLOAT2(x, y += step)); + pauseCheckBox->OnClick([&](wiEventArgs args) { + auto emitter = GetEmitter(); + if (emitter != nullptr) + { + emitter->PAUSED = args.bValue; + } + }); + pauseCheckBox->SetCheck(false); + pauseCheckBox->SetTooltip("Stop simulation update."); + emitterWindow->AddWidget(pauseCheckBox); + + debugCheckBox = new wiCheckBox("DEBUG: "); - debugCheckBox->SetPos(XMFLOAT2(x + 500, y)); + debugCheckBox->SetPos(XMFLOAT2(x + 120, y)); debugCheckBox->OnClick([&](wiEventArgs args) { auto emitter = GetEmitter(); if (emitter != nullptr) @@ -435,6 +449,8 @@ void EmitterWindow::SetObject(Object* obj) { sortCheckBox->SetCheck(emitter->SORTING); depthCollisionsCheckBox->SetCheck(emitter->DEPTHCOLLISIONS); + sphCheckBox->SetCheck(emitter->SPH_FLUIDSIMULATION); + pauseCheckBox->SetCheck(emitter->PAUSED); maxParticlesSlider->SetValue((float)emitter->GetMaxParticleCount()); emitCountSlider->SetValue(emitter->count); diff --git a/Editor/EmitterWindow.h b/Editor/EmitterWindow.h index 9c185be47..fa2ac6616 100644 --- a/Editor/EmitterWindow.h +++ b/Editor/EmitterWindow.h @@ -38,6 +38,7 @@ public: wiCheckBox* sortCheckBox; wiCheckBox* depthCollisionsCheckBox; wiCheckBox* sphCheckBox; + wiCheckBox* pauseCheckBox; wiCheckBox* debugCheckBox; wiSlider* emitCountSlider; wiSlider* emitSizeSlider; diff --git a/WickedEngine/emittedparticle_kickoffSortCS.hlsl b/WickedEngine/emittedparticle_kickoffSortCS.hlsl index e76c7902b..fab185a57 100644 --- a/WickedEngine/emittedparticle_kickoffSortCS.hlsl +++ b/WickedEngine/emittedparticle_kickoffSortCS.hlsl @@ -8,13 +8,13 @@ RWRAWBUFFER(indirectBuffers, 5); void main( uint3 DTid : SV_DispatchThreadID ) { // read real alivecount from after simulation: - uint aliveCount_afterSimulation = indirectBuffers.Load(24) / 6; + int aliveCount_afterSimulation = indirectBuffers.Load(24) / 6; // and store it for the sorting shaders to read: counterBuffer[0].aliveCount_afterSimulation = aliveCount_afterSimulation; // calculate threadcount: - uint threadCount = ((max(1, aliveCount_afterSimulation) - 1) >> 9) + 1; + uint threadCount = ((aliveCount_afterSimulation - 1) >> 9) + 1; // and prepare to dispatch the sort for the alive simulated particles: indirectBuffers.Store3(ARGUMENTBUFFER_OFFSET_DISPATCHSORT, uint3(threadCount, 1, 1)); diff --git a/WickedEngine/emittedparticle_simulateCS.hlsl b/WickedEngine/emittedparticle_simulateCS.hlsl index 581ea53db..d7acabafb 100644 --- a/WickedEngine/emittedparticle_simulateCS.hlsl +++ b/WickedEngine/emittedparticle_simulateCS.hlsl @@ -58,6 +58,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint Gid : SV_GroupIndex) { // simulate: + float3 force = 0; for (uint i = 0; i < numForceFields; ++i) { LDS_ForceField forceField = forceFields[i]; @@ -74,10 +75,9 @@ void main(uint3 DTid : SV_DispatchThreadID, uint Gid : SV_GroupIndex) dir = forceField.normal; } - float3 force = dir * forceField.gravity * (1 - saturate(dist * forceField.range_inverse)); - - particle.velocity += force * dt; + force += dir * forceField.gravity * (1 - saturate(dist * forceField.range_inverse)); } + particle.velocity += force * dt; #ifdef DEPTHCOLLISIONS @@ -112,7 +112,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint Gid : SV_GroupIndex) float3 surfaceNormal = normalize(cross(p2 - p0, p1 - p0)); - const float restitution = 0.4f; + const float restitution = 0.98f; particle.velocity = reflect(particle.velocity, surfaceNormal) * restitution; } } diff --git a/WickedEngine/emittedparticle_sortCS.hlsl b/WickedEngine/emittedparticle_sortCS.hlsl index 61c0d971b..fd144fb44 100644 --- a/WickedEngine/emittedparticle_sortCS.hlsl +++ b/WickedEngine/emittedparticle_sortCS.hlsl @@ -22,7 +22,7 @@ #include "ShaderInterop_EmittedParticle.h" -#define SORT_SIZE 4096 +#define SORT_SIZE 512 #if( SORT_SIZE>4096 ) // won't work for arrays>4096 @@ -65,12 +65,12 @@ void main(uint3 Gid : SV_GroupID, // Load shared data uint i; - [unroll]for (i = 0; i<2 * ITERATIONS; ++i) + [unroll]for (i = 0; i < 2 * ITERATIONS; ++i) { - if (GI + i*NUM_THREADS < numElementsInThreadGroup) + if (GI + i * NUM_THREADS < numElementsInThreadGroup) { - uint loadIndex = GlobalBaseIndex + i*NUM_THREADS; - g_LDS[LocalBaseIndex + i*NUM_THREADS] = float2(distanceBuffer[loadIndex], (float)indexBuffer[loadIndex]); + uint loadIndex = GlobalBaseIndex + i * NUM_THREADS; + g_LDS[LocalBaseIndex + i * NUM_THREADS] = float2(distanceBuffer[loadIndex], (float)indexBuffer[loadIndex]); } } GroupMemoryBarrierWithGroupSync(); @@ -78,9 +78,9 @@ void main(uint3 Gid : SV_GroupID, // Bitonic sort for (unsigned int nMergeSize = 2; nMergeSize <= SORT_SIZE; nMergeSize = nMergeSize * 2) { - for (uint nMergeSubSize = nMergeSize >> 1; nMergeSubSize>0; nMergeSubSize = nMergeSubSize >> 1) + for (uint nMergeSubSize = nMergeSize >> 1; nMergeSubSize > 0; nMergeSubSize = nMergeSubSize >> 1) { - [unroll]for (i = 0; i> 1 ? index_high + (2 * nMergeSubSize - 1) - index_low : index_high + nMergeSubSize + index_low; - if (nSwapElem2048 ) #error @@ -65,18 +65,18 @@ void main(uint3 Gid : SV_GroupID, uint i; // Load shared data - [unroll]for (i = 0; i<2; ++i) + [unroll]for (i = 0; i < 2; ++i) { - if (GI + i*NUM_THREADS < tgp.w) + if (GI + i * NUM_THREADS < tgp.w) { - uint loadIndex = GlobalBaseIndex + i*NUM_THREADS; - g_LDS[LocalBaseIndex + i*NUM_THREADS] = float2(distanceBuffer[loadIndex], (float)indexBuffer[loadIndex]); + uint loadIndex = GlobalBaseIndex + i * NUM_THREADS; + g_LDS[LocalBaseIndex + i * NUM_THREADS] = float2(distanceBuffer[loadIndex], (float)indexBuffer[loadIndex]); } } GroupMemoryBarrierWithGroupSync(); // sort threadgroup shared memory - for (int nMergeSubSize = SORT_SIZE >> 1; nMergeSubSize>0; nMergeSubSize = nMergeSubSize >> 1) + for (int nMergeSubSize = SORT_SIZE >> 1; nMergeSubSize > 0; nMergeSubSize = nMergeSubSize >> 1) { int tmp_index = GI; int index_low = tmp_index & (nMergeSubSize - 1); @@ -85,7 +85,7 @@ void main(uint3 Gid : SV_GroupID, unsigned int nSwapElem = index_high + nMergeSubSize + index_low; - if (nSwapElem extent.x) { particleA.position.x = extent.x - particleSize; diff --git a/WickedEngine/wiEmittedParticle.cpp b/WickedEngine/wiEmittedParticle.cpp index 0b0385134..a9bd9a34c 100644 --- a/WickedEngine/wiEmittedParticle.cpp +++ b/WickedEngine/wiEmittedParticle.cpp @@ -269,6 +269,7 @@ uint32_t wiEmittedParticle::GetMemorySizeInBytes() const retVal += aliveList[1]->GetDesc().ByteWidth; retVal += deadList->GetDesc().ByteWidth; retVal += distanceBuffer->GetDesc().ByteWidth; + retVal += densityBuffer->GetDesc().ByteWidth; retVal += counterBuffer->GetDesc().ByteWidth; retVal += indirectBuffers->GetDesc().ByteWidth; retVal += constantBuffer->GetDesc().ByteWidth; @@ -283,15 +284,22 @@ XMFLOAT3 wiEmittedParticle::GetPosition() const void wiEmittedParticle::Update(float dt) { + if (PAUSED) + return; + emit += (float)count*dt; } void wiEmittedParticle::Burst(float num) { + if (PAUSED) + return; + emit += num; } void wiEmittedParticle::Restart() { buffersUpToDate = false; + PAUSED = false; } @@ -300,7 +308,7 @@ void wiEmittedParticle::UpdateRenderData(GRAPHICSTHREAD threadID) CreateSelfBuffers(); GraphicsDevice* device = wiRenderer::GetDevice(); - device->EventBegin("UpdateEmittedParticles", threadID); + EmittedParticleCB cb; cb.xEmitterWorld = object->world; @@ -344,7 +352,7 @@ void wiEmittedParticle::UpdateRenderData(GRAPHICSTHREAD threadID) distanceBuffer, }; device->BindUnorderedAccessResourcesCS(uavs, 0, ARRAYSIZE(uavs), threadID); - + GPUResource* resources[] = { wiTextureHelper::getInstance()->getRandom64x64(), object->mesh->indexBuffer, @@ -352,93 +360,100 @@ void wiEmittedParticle::UpdateRenderData(GRAPHICSTHREAD threadID) }; device->BindResources(CS, resources, TEXSLOT_ONDEMAND0, ARRAYSIZE(resources), threadID); - GPUResource* indres[] = { - indirectBuffers - }; - device->TransitionBarrier(indres, 1, RESOURCE_STATE_INDIRECT_ARGUMENT, RESOURCE_STATE_UNORDERED_ACCESS, threadID); - - // kick off updating, set up state - device->BindComputePSO(&CPSO_kickoffUpdate, threadID); - device->Dispatch(1, 1, 1, threadID); - device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID); - - device->TransitionBarrier(indres, 1, RESOURCE_STATE_UNORDERED_ACCESS, RESOURCE_STATE_INDIRECT_ARGUMENT, threadID); - - // emit the required amount if there are free slots in dead list - device->BindComputePSO(&CPSO_emit, threadID); - device->DispatchIndirect(indirectBuffers, ARGUMENTBUFFER_OFFSET_DISPATCHEMIT, threadID); - device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID); - - if (SPH_FLUIDSIMULATION) + if (!PAUSED) { - // Smooth Particle Hydrodynamics: - // 1.) Compute particle density field: - device->BindComputePSO(&CPSO_sphdensity, threadID); - device->UnBindUnorderedAccessResources(0, 8, threadID); - GPUResource* res_density[] = { - aliveList[0], // CURRENT alivelist - counterBuffer, + device->EventBegin("UpdateEmittedParticles", threadID); + + GPUResource* indres[] = { + indirectBuffers }; - device->BindResources(CS, res_density, 0, ARRAYSIZE(res_density), threadID); - GPUResource* uav_density[] = { - particleBuffer, - densityBuffer - }; - device->BindUnorderedAccessResourcesCS(uav_density, 0, ARRAYSIZE(uav_density), threadID); - device->DispatchIndirect(indirectBuffers, ARGUMENTBUFFER_OFFSET_DISPATCHSIMULATION, threadID); + device->TransitionBarrier(indres, 1, RESOURCE_STATE_INDIRECT_ARGUMENT, RESOURCE_STATE_UNORDERED_ACCESS, threadID); + + // kick off updating, set up state + device->BindComputePSO(&CPSO_kickoffUpdate, threadID); + device->Dispatch(1, 1, 1, threadID); device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID); - // 2.) Compute particle pressure forces: - device->BindComputePSO(&CPSO_sphforce, threadID); - device->UnBindUnorderedAccessResources(0, 8, threadID); - GPUResource* res_force[] = { - aliveList[0], // CURRENT alivelist - counterBuffer, - densityBuffer - }; - device->BindResources(CS, res_force, 0, ARRAYSIZE(res_force), threadID); - GPUResource* uav_force[] = { - particleBuffer, - }; - device->BindUnorderedAccessResourcesCS(uav_force, 0, ARRAYSIZE(uav_force), threadID); - device->DispatchIndirect(indirectBuffers, ARGUMENTBUFFER_OFFSET_DISPATCHSIMULATION, threadID); + device->TransitionBarrier(indres, 1, RESOURCE_STATE_UNORDERED_ACCESS, RESOURCE_STATE_INDIRECT_ARGUMENT, threadID); + + // emit the required amount if there are free slots in dead list + device->BindComputePSO(&CPSO_emit, threadID); + device->DispatchIndirect(indirectBuffers, ARGUMENTBUFFER_OFFSET_DISPATCHEMIT, threadID); device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID); - device->UnBindResources(0, 3, threadID); - device->UnBindUnorderedAccessResources(0, 8, threadID); - } - - device->BindUnorderedAccessResourcesCS(uavs, 0, ARRAYSIZE(uavs), threadID); - device->BindResources(CS, resources, TEXSLOT_ONDEMAND0, ARRAYSIZE(resources), threadID); - - // update CURRENT alive list, write NEW alive list - if (SORTING) - { - if (DEPTHCOLLISIONS) + if (SPH_FLUIDSIMULATION) { - device->BindComputePSO(&CPSO_simulate_SORTING_DEPTHCOLLISIONS, threadID); + // Smooth Particle Hydrodynamics: + + // 1.) Compute particle density field: + device->BindComputePSO(&CPSO_sphdensity, threadID); + device->UnBindUnorderedAccessResources(0, 8, threadID); + GPUResource* res_density[] = { + aliveList[0], // CURRENT alivelist + counterBuffer, + }; + device->BindResources(CS, res_density, 0, ARRAYSIZE(res_density), threadID); + GPUResource* uav_density[] = { + particleBuffer, + densityBuffer + }; + device->BindUnorderedAccessResourcesCS(uav_density, 0, ARRAYSIZE(uav_density), threadID); + device->DispatchIndirect(indirectBuffers, ARGUMENTBUFFER_OFFSET_DISPATCHSIMULATION, threadID); + device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID); + + // 2.) Compute particle pressure forces: + device->BindComputePSO(&CPSO_sphforce, threadID); + device->UnBindUnorderedAccessResources(0, 8, threadID); + GPUResource* res_force[] = { + aliveList[0], // CURRENT alivelist + counterBuffer, + densityBuffer + }; + device->BindResources(CS, res_force, 0, ARRAYSIZE(res_force), threadID); + GPUResource* uav_force[] = { + particleBuffer, + }; + device->BindUnorderedAccessResourcesCS(uav_force, 0, ARRAYSIZE(uav_force), threadID); + device->DispatchIndirect(indirectBuffers, ARGUMENTBUFFER_OFFSET_DISPATCHSIMULATION, threadID); + device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID); + + device->UnBindResources(0, 3, threadID); + device->UnBindUnorderedAccessResources(0, 8, threadID); + } + + device->BindUnorderedAccessResourcesCS(uavs, 0, ARRAYSIZE(uavs), threadID); + device->BindResources(CS, resources, TEXSLOT_ONDEMAND0, ARRAYSIZE(resources), threadID); + + // update CURRENT alive list, write NEW alive list + if (SORTING) + { + if (DEPTHCOLLISIONS) + { + device->BindComputePSO(&CPSO_simulate_SORTING_DEPTHCOLLISIONS, threadID); + } + else + { + device->BindComputePSO(&CPSO_simulate_SORTING, threadID); + } } else { - device->BindComputePSO(&CPSO_simulate_SORTING, threadID); + if (DEPTHCOLLISIONS) + { + device->BindComputePSO(&CPSO_simulate_DEPTHCOLLISIONS, threadID); + } + else + { + device->BindComputePSO(&CPSO_simulate, threadID); + } } - } - else - { - if (DEPTHCOLLISIONS) - { - device->BindComputePSO(&CPSO_simulate_DEPTHCOLLISIONS, threadID); - } - else - { - device->BindComputePSO(&CPSO_simulate, threadID); - } - } - device->DispatchIndirect(indirectBuffers, ARGUMENTBUFFER_OFFSET_DISPATCHSIMULATION, threadID); - device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID); + device->DispatchIndirect(indirectBuffers, ARGUMENTBUFFER_OFFSET_DISPATCHSIMULATION, threadID); + device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID); - device->EventEnd(threadID); + device->EventEnd(threadID); + + } if (SORTING) { @@ -449,48 +464,55 @@ void wiEmittedParticle::UpdateRenderData(GRAPHICSTHREAD threadID) device->Dispatch(1, 1, 1, threadID); device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID); - // initial sorting: - bool bDone = true; + //// initial sorting: + //bool bDone = true; + //{ + // // calculate how many threads we'll require: + // // we'll sort 512 elements per CU (threadgroupsize 256) + // // maybe need to optimize this or make it changeable during init + // // TGS=256 is a good intermediate value - // calculate how many threads we'll require: - // we'll sort 512 elements per CU (threadgroupsize 256) - // maybe need to optimize this or make it changeable during init - // TGS=256 is a good intermediate value + // unsigned int numThreadGroups = ((MAX_PARTICLES - 1) >> 9) + 1; - unsigned int numThreadGroups = ((MAX_PARTICLES - 1) >> 9) + 1; + // assert(numThreadGroups <= 1024); - if (numThreadGroups > 1) - { - bDone = false; - } + // if (numThreadGroups > 1) + // { + // bDone = false; + // } - // sort all buffers of size 512 (and presort bigger ones) - device->BindComputePSO(&CPSO_sort, threadID); - device->DispatchIndirect(indirectBuffers, ARGUMENTBUFFER_OFFSET_DISPATCHSORT, threadID); - device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID); + // // sort all buffers of size 512 (and presort bigger ones) + // device->BindComputePSO(&CPSO_sort, threadID); + // device->DispatchIndirect(indirectBuffers, ARGUMENTBUFFER_OFFSET_DISPATCHSORT, threadID); + // device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID); + //} + + bool bDone = false; int presorted = 512; while (!bDone) { + // Incremental sorting: + bDone = true; device->BindComputePSO(&CPSO_sortStep, threadID); // prepare thread group description data - unsigned int numThreadGroups = 0; + uint32_t numThreadGroups = 0; if (MAX_PARTICLES > (uint32_t)presorted) { - if (MAX_PARTICLES>(uint32_t)presorted * 2) + if (MAX_PARTICLES > (uint32_t)presorted * 2) bDone = false; - unsigned int pow2 = presorted; - while (pow2> 9; } - unsigned int nMergeSize = presorted * 2; - for (unsigned int nMergeSubSize = nMergeSize >> 1; nMergeSubSize>256; nMergeSubSize = nMergeSubSize >> 1) + uint32_t nMergeSize = presorted * 2; + for (uint32_t nMergeSubSize = nMergeSize >> 1; nMergeSubSize > 256; nMergeSubSize = nMergeSubSize >> 1) { SortConstants sc; sc.job_params.x = nMergeSubSize; @@ -507,15 +529,14 @@ void wiEmittedParticle::UpdateRenderData(GRAPHICSTHREAD threadID) sc.job_params.w = 0; device->UpdateBuffer(sortCB, &sc, threadID); - + device->Dispatch(numThreadGroups, 1, 1, threadID); device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID); } - device->BindComputePSO(&CPSO_sortInner, threadID); - device->Dispatch(numThreadGroups, 1, 1, threadID); - device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID); - + //device->BindComputePSO(&CPSO_sortInner, threadID); + //device->Dispatch(numThreadGroups, 1, 1, threadID); + //device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID); presorted *= 2; } diff --git a/WickedEngine/wiEmittedParticle.h b/WickedEngine/wiEmittedParticle.h index c56de2de1..399343bb0 100644 --- a/WickedEngine/wiEmittedParticle.h +++ b/WickedEngine/wiEmittedParticle.h @@ -79,6 +79,7 @@ public: bool DEBUG = false; ParticleCounters GetDebugData() { return debugData; } + bool PAUSED = false; bool SORTING = false; bool DEPTHCOLLISIONS = false; diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 133d0490e..73cf50c88 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wiVersion // minor features, major updates const int minor = 17; // minor bug fixes, alterations, refactors, updates - const int revision = 12; + const int revision = 13; long GetVersion()