Improved particles and trajectory rendering #430
|
@ -118,6 +118,9 @@ void main()
|
|||
|
||||
if (particle.life > 0.0f)
|
||||
{
|
||||
// update position from velocity
|
||||
// particle.position += particle.velocity * genericDataBuffer.data.dt;
|
||||
// particle.life -= genericDataBuffer.data.dt;
|
||||
|
||||
if (particle.life < 0.0f || particle.scaleAndDecay.x < 0.0f || particle.scaleAndDecay.y < 0.0f)
|
||||
{
|
||||
|
|
|
@ -78,8 +78,11 @@ void main()
|
|||
vec2 particleScaleData = particle.scaleAndDecay.xz; // x and y
|
||||
|
||||
mat4 localModel = mat4 (1.0f);
|
||||
localModel[0][0] = particleScaleData.x;
|
||||
localModel[1][1] = particleScaleData.y;
|
||||
localModel[0][0] = 1.0f;
|
||||
localModel[1][1] = 1.0f;
|
||||
|
||||
// localModel[0][0] = particleScaleData.x;
|
||||
// localModel[1][1] = particleScaleData.y;
|
||||
|
||||
mat4 rotate = mat4(1.0f);
|
||||
rotate[0][0] = cos(angle);
|
||||
|
@ -89,6 +92,6 @@ void main()
|
|||
// localModel = rotate * localModel;
|
||||
|
||||
localModel[3] = vec4 (particle.position.xyz, 1.0f);
|
||||
gl_Position = cameraData.vpMat * localModel * vec4(vertexPos, 1.0f);
|
||||
// gl_Position = vec4(vertexPos, 1.0f);
|
||||
// gl_Position = cameraData.vpMat * localModel * vec4(vertexPos, 1.0f);
|
||||
gl_Position = vec4(vertexPos, 1.0f);
|
||||
}
|
Binary file not shown.
|
@ -251,7 +251,7 @@ namespace SHADE
|
|||
// particle draw call binding
|
||||
SHVkDescriptorSetLayout::Binding particleDrawDataBinding
|
||||
{
|
||||
.Type = vk::DescriptorType::eStorageBufferDynamic, // UBO (Because lesser data), dynamic (1 set for each frame)
|
||||
.Type = vk::DescriptorType::eStorageBufferDynamic, // SSBO, dynamic (1 set for each frame)
|
||||
.Stage = vk::ShaderStageFlagBits::eCompute,
|
||||
.BindPoint = SHGraphicsConstants::DescriptorSetBindings::PARTICLE_DRAW_DATA,
|
||||
.DescriptorCount = 1,
|
||||
|
|
|
@ -707,9 +707,11 @@ namespace SHADE
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
renderGraph->Begin(frameIndex);
|
||||
auto cmdBuffer = renderGraph->GetCommandBuffer(frameIndex);
|
||||
|
||||
particleSubSystem->ResetInstanceCounts(cmdBuffer, frameIndex);
|
||||
particleSubSystem->Run(cmdBuffer, frameIndex);
|
||||
|
||||
renderGraph->Execute(frameIndex, descPool, MESH_DATA);
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include "Graphics/Pipeline/SHVkPipeline.h"
|
||||
#include "Graphics/RenderGraph/SHSubpass.h"
|
||||
#include "Graphics/SHVkUtil.h"
|
||||
#include "Graphics/Synchronization/SHVkFence.h"
|
||||
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
@ -68,7 +70,7 @@ namespace SHADE
|
|||
}
|
||||
|
||||
// buffer to store draw call data. Non-indexed, host-visible mapped, triple buffered.
|
||||
comp.drawCallData = logicalDevice->CreateBuffer(SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmdAligned, indirectCommands.data(), SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmdAligned, vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndirectBuffer, VMA_MEMORY_USAGE_AUTO, VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT);
|
||||
comp.drawCallData = logicalDevice->CreateBuffer(SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmdAligned, indirectCommands.data(), SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmdAligned, vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndirectBuffer, VMA_MEMORY_USAGE_AUTO, VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT);
|
||||
|
||||
}
|
||||
|
||||
|
@ -151,12 +153,6 @@ namespace SHADE
|
|||
{
|
||||
auto const& mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING);
|
||||
|
||||
uint32_t instanceCountOffset = sizeof (vk::DrawIndirectCommand) * frameIndex + offsetof(vk::DrawIndirectCommand, instanceCount);
|
||||
uint32_t ZERO = 0;
|
||||
|
||||
// reset instance count to 0
|
||||
comp.drawCallData->WriteToMemory (&ZERO, sizeof(uint32_t), 0, instanceCountOffset);
|
||||
|
||||
// bind the descriptor sets required for emitting particles
|
||||
cmdBuffer->BindDescriptorSet(comp.particleDescriptorSet, SH_PIPELINE_TYPE::COMPUTE, mappings.at(SHPredefinedDescriptorTypes::PARTICLES), comp.dynamicOffsets[frameIndex]);
|
||||
|
||||
|
@ -170,7 +166,7 @@ namespace SHADE
|
|||
//cmdBuffer->DrawArrays(4, 1, 0, 0);
|
||||
}
|
||||
|
||||
void SHParticleSubSystem::PreparePrePostUpdateBarriers(std::vector<vk::BufferMemoryBarrier>& preUpdateBarriers, std::vector<vk::BufferMemoryBarrier>& postUpdateBarriers, SHParticleEmitterComponent const& emitter, uint32_t const EMITTER_INDEX, uint32_t const FRAME_INDEX) noexcept
|
||||
void SHParticleSubSystem::PreparePrePostUpdateBarriers(std::vector<vk::BufferMemoryBarrier>& preUpdateBarriers, std::vector<vk::BufferMemoryBarrier>& postUpdateBarriers, std::vector<vk::BufferMemoryBarrier>& preDrawBarriers, SHParticleEmitterComponent const& emitter, uint32_t const EMITTER_INDEX, uint32_t const FRAME_INDEX) noexcept
|
||||
{
|
||||
// pre-update particles data barrier. Note that this is for input because we want the input to be available before we use it.
|
||||
vk::BufferMemoryBarrier particleDataBarrier
|
||||
|
@ -219,18 +215,17 @@ namespace SHADE
|
|||
// make new barrier on stack...
|
||||
vk::BufferMemoryBarrier drawDataBarrier
|
||||
{
|
||||
.srcAccessMask = vk::AccessFlagBits::eShaderWrite,
|
||||
.dstAccessMask = vk::AccessFlagBits::eShaderRead,
|
||||
.srcAccessMask = vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eMemoryWrite,
|
||||
.dstAccessMask = vk::AccessFlagBits::eIndirectCommandRead,
|
||||
.buffer = emitter.drawCallData->GetVkBuffer(),
|
||||
.offset = emitter.dynamicOffsets[FRAME_INDEX][DYOFF_INDEX_DRAW_DATA],
|
||||
.size = static_cast<uint32_t>(sizeof(vk::DrawIndirectCommand))
|
||||
};
|
||||
|
||||
// ...copy assign barriers on heap
|
||||
postUpdateBarriers[EMITTER_INDEX * 3] = particleDataBarrierPost;
|
||||
postUpdateBarriers[(EMITTER_INDEX * 3) + 1] = indicesDataBarrier;
|
||||
postUpdateBarriers[(EMITTER_INDEX * 3) + 2] = drawDataBarrier;
|
||||
|
||||
postUpdateBarriers[EMITTER_INDEX * 2] = particleDataBarrierPost;
|
||||
postUpdateBarriers[(EMITTER_INDEX * 2) + 1] = indicesDataBarrier;
|
||||
preDrawBarriers[EMITTER_INDEX] = drawDataBarrier;
|
||||
}
|
||||
|
||||
void SHParticleSubSystem::Init(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> inDescPool, Handle<SHVkRenderpass> compatibleRenderpass, Handle<SHSubpass> subpass, Handle<SHVkShaderModule> VS, Handle<SHVkShaderModule> FS, Handle<SHVkShaderModule> emitCS, Handle<SHVkShaderModule> defaultUpdateCS) noexcept
|
||||
|
@ -310,7 +305,7 @@ namespace SHADE
|
|||
SHComponentManager::CreateComponentSparseSet<SHParticleEmitterComponent>();
|
||||
}
|
||||
|
||||
void SHParticleSubSystem::Run(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
|
||||
void SHParticleSubSystem::Run(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, Handle<SHVkFence> waitFence) noexcept
|
||||
{
|
||||
float dt = static_cast<float>(SHFrameRateController::GetRawDeltaTime());
|
||||
|
||||
|
@ -332,7 +327,11 @@ namespace SHADE
|
|||
// After we invoke the updates for the emitters, we need to make sure all particles and indices data are done updating
|
||||
// before we issue them for rendering.
|
||||
std::vector<vk::BufferMemoryBarrier> postUpdateBarriers{};
|
||||
postUpdateBarriers.resize(emitters.size() * 3);
|
||||
postUpdateBarriers.resize(emitters.size() * 2);
|
||||
|
||||
std::vector<vk::BufferMemoryBarrier> preDrawBarriers{};
|
||||
preDrawBarriers.resize(emitters.size());
|
||||
|
||||
|
||||
// If we wanted to be VERY safe, a barrier would be good here to make sure output particles have finish reading input particles in
|
||||
// the update compute. HOWEVER since a NUM_FRAME_BUFFERS frames would have passed by then, we will not insert 1 here.
|
||||
|
@ -350,6 +349,10 @@ namespace SHADE
|
|||
SHGlobalDescriptorSets::BindGenericAndTextureData(logicalDevice, cmdBuffer, SH_PIPELINE_TYPE::COMPUTE, mappings.at(SHPredefinedDescriptorTypes::STATIC_DATA), frameIndex);
|
||||
|
||||
uint32_t i = 0;
|
||||
|
||||
if (waitFence)
|
||||
waitFence->Wait(true);
|
||||
|
||||
for (auto& emitter : emitters)
|
||||
{
|
||||
if (!emitter.initialized)
|
||||
|
@ -382,7 +385,7 @@ namespace SHADE
|
|||
}
|
||||
|
||||
// prepare barriers
|
||||
PreparePrePostUpdateBarriers(preUpdateBarriers, postUpdateBarriers, emitter, i, frameIndex);
|
||||
PreparePrePostUpdateBarriers(preUpdateBarriers, postUpdateBarriers, preDrawBarriers, emitter, i, frameIndex);
|
||||
|
||||
// Emitter will emit once and stop emitting next frame (unless specified before reaching here to do so).
|
||||
emitter.toEmit = false;
|
||||
|
@ -398,6 +401,7 @@ namespace SHADE
|
|||
/* EMITTING PARTICLES DONE, BEGIN UPDATES.... */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// bind the pipeline for updating
|
||||
cmdBuffer->BindPipeline(defaultUpdatePipelineData.pipeline);
|
||||
|
||||
|
@ -411,9 +415,53 @@ namespace SHADE
|
|||
/*-----------------------------------------------------------------------*/
|
||||
// issue the barrier to wait for output particles to be done updating and indices data to finish being modified.
|
||||
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {}, postUpdateBarriers, {});
|
||||
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eDrawIndirect, {}, {}, preDrawBarriers, {});
|
||||
|
||||
}
|
||||
|
||||
void SHParticleSubSystem::ResetInstanceCounts(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
|
||||
{
|
||||
auto& emitters = SHComponentManager::GetDense<SHParticleEmitterComponent>();
|
||||
std::vector<vk::BufferMemoryBarrier> preResetBarriers{};
|
||||
preResetBarriers.resize(emitters.size());
|
||||
|
||||
uint32_t i = 0;
|
||||
for (auto& emitter : emitters)
|
||||
{
|
||||
if (emitter.initialized)
|
||||
{
|
||||
// pre-update particles data barrier. Note that this is for input because we want the input to be available before we use it.
|
||||
vk::BufferMemoryBarrier drawDataHostWriteBarrier
|
||||
{
|
||||
.srcAccessMask = vk::AccessFlagBits::eIndirectCommandRead | vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite,
|
||||
.dstAccessMask = vk::AccessFlagBits::eMemoryWrite | vk::AccessFlagBits::eHostWrite,
|
||||
.buffer = emitter.drawCallData->GetVkBuffer(),
|
||||
.offset = emitter.dynamicOffsets[frameIndex][DYOFF_INDEX_DRAW_DATA],
|
||||
.size = static_cast<uint32_t>(sizeof(vk::DrawIndirectCommand))
|
||||
};
|
||||
|
||||
preResetBarriers[i] = drawDataHostWriteBarrier;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eDrawIndirect, vk::PipelineStageFlagBits::eHost, {}, {}, preResetBarriers, {});
|
||||
|
||||
|
||||
for (auto& emitter : emitters)
|
||||
{
|
||||
if (emitter.initialized)
|
||||
{
|
||||
//uint32_t instanceCountOffset = 20;
|
||||
uint32_t instanceCountOffset = sizeof(vk::DrawIndirectCommand) * frameIndex + offsetof(vk::DrawIndirectCommand, instanceCount);
|
||||
uint32_t ZERO = 0;
|
||||
|
||||
// reset instance count to 0
|
||||
emitter.drawCallData->WriteToMemory(&ZERO, sizeof(uint32_t), 0, instanceCountOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SHParticleSubSystem::Render(Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex) noexcept
|
||||
{
|
||||
auto& emitters = SHComponentManager::GetDense<SHParticleEmitterComponent>();
|
||||
|
@ -432,6 +480,7 @@ namespace SHADE
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void SHParticleSubSystem::Exit(void) noexcept
|
||||
{
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace SHADE
|
|||
class SHVkShaderModule;
|
||||
class SHRenderer;
|
||||
class SHParticleEmitterComponent;
|
||||
class SHVkFence;
|
||||
|
||||
|
||||
|
||||
|
@ -81,12 +82,13 @@ namespace SHADE
|
|||
void UpdateCompoennt(Handle<SHVkCommandBuffer> cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept;
|
||||
void RenderComponent(Handle<SHVkCommandBuffer> cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept;
|
||||
|
||||
void PreparePrePostUpdateBarriers (std::vector<vk::BufferMemoryBarrier>& preUpdateBarriers, std::vector<vk::BufferMemoryBarrier>& postUpdateBarriers, SHParticleEmitterComponent const& emitter, uint32_t const EMITTER_INDEX, uint32_t const FRAME_INDEX) noexcept;
|
||||
void PreparePrePostUpdateBarriers (std::vector<vk::BufferMemoryBarrier>& preUpdateBarriers, std::vector<vk::BufferMemoryBarrier>& postUpdateBarriers, std::vector<vk::BufferMemoryBarrier>& preDrawBarriers, SHParticleEmitterComponent const& emitter, uint32_t const EMITTER_INDEX, uint32_t const FRAME_INDEX) noexcept;
|
||||
|
||||
public:
|
||||
void Init(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> inDescPool, Handle<SHVkRenderpass> compatibleRenderpass, Handle<SHSubpass> subpass, Handle<SHVkShaderModule> VS, Handle<SHVkShaderModule> FS, Handle<SHVkShaderModule> emitCS, Handle<SHVkShaderModule> defaultUpdateCS) noexcept;
|
||||
|
||||
void Run(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
|
||||
void Run(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, Handle<SHVkFence> waitFence = {}) noexcept;
|
||||
void ResetInstanceCounts (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
|
||||
|
||||
void Render(Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex) noexcept;
|
||||
void Exit(void) noexcept;
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace SHADE
|
|||
/*-----------------------------------------------------------------------*/
|
||||
/* PUBLIC MEMBER FUNCTIONS */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
bool Wait (bool waitAll, uint64_t timer) noexcept;
|
||||
bool Wait (bool waitAll, uint64_t timer = std::numeric_limits<uint32_t>::max()) noexcept;
|
||||
void Reset (void) noexcept;
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
|
Loading…
Reference in New Issue