Improved particles and trajectory rendering #430
|
@ -7,7 +7,7 @@ struct EmitterParameters
|
|||
vec4 angularMin;
|
||||
vec4 angularMax;
|
||||
vec4 lifeAndSizeRange; // min life, max life, min size, max size
|
||||
}
|
||||
};
|
||||
|
||||
struct ParticleData
|
||||
{
|
||||
|
@ -18,7 +18,7 @@ struct ParticleData
|
|||
vec4 scaleAndDecay;
|
||||
float life;
|
||||
uint textureIndex;
|
||||
}
|
||||
};
|
||||
|
||||
struct GenericData
|
||||
{
|
||||
|
@ -96,9 +96,15 @@ float rand(inout uint state)
|
|||
return float(x)*uintBitsToFloat(0x2f800004u);
|
||||
}
|
||||
|
||||
float map(float value, float inMin, float inMax, float outMin, float outMax)
|
||||
{
|
||||
return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
uint emitterInvocationIndex = gl_GlobalInvocationID.x;
|
||||
vec4 emitterPosition = emitterPushConstant.emitterPosition;
|
||||
|
||||
if (emitterInvocationIndex >= emitterPushConstant.emissionCount)
|
||||
return;
|
||||
|
@ -109,9 +115,18 @@ void main()
|
|||
|
||||
ParticleData particle;
|
||||
|
||||
int index = freelist.freeIndices[freelistIndex];
|
||||
particle.position = emitterPosition;
|
||||
particle.life = emitterParams.10.0f;
|
||||
// Get seed for randomization
|
||||
uint pixel_index = uint (emitterPosition.x + emitterPosition.y + floatBitsToUint(genericDataBuffer.data.elapsedTime) * (gl_GlobalInvocationID.x + 1));
|
||||
uint seed = pcg_hash (pixel_index);
|
||||
|
||||
particles[index] = particle;
|
||||
int index = freelist.freeIndices[freelistIndex];
|
||||
|
||||
// emit particle from emitter position
|
||||
particle.position = vec4 (emitterPosition.xyz, 1.0f);
|
||||
|
||||
// randomize life value that ranges from minLife to maxLife
|
||||
particle.life = map (rand(seed), -1.0f, 1.0f, emitterParams.data.lifeAndSizeRange.x, emitterParams.data.lifeAndSizeRange.y);
|
||||
|
||||
|
||||
inputParticles.data[index] = particle;
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
|||
Name: ParticleEmit_CS
|
||||
ID: 49959611
|
||||
Type: 2
|
|
@ -19,7 +19,7 @@ struct ParticleData
|
|||
vec4 scaleAndDecay;
|
||||
float life;
|
||||
uint textureIndex;
|
||||
}
|
||||
};
|
||||
|
||||
struct GenericData
|
||||
{
|
||||
|
@ -73,7 +73,7 @@ layout (std430, set = 2, binding = 4) coherent restrict buffer IndicesData
|
|||
uint indices[];
|
||||
};
|
||||
|
||||
layout (std140, set = 2, binding = 5) coherent restrict uniform IndirectDrawArgs
|
||||
layout (std140, set = 2, binding = 5) coherent restrict buffer IndirectDrawArgs
|
||||
{
|
||||
DrawArraysIndirectArgs indirectArgs;
|
||||
};
|
||||
|
@ -116,17 +116,12 @@ void main()
|
|||
|
||||
ParticleData particle = inputParticles.data[index];
|
||||
|
||||
if (particle.lifetime > 0.0f)
|
||||
if (particle.life > 0.0f)
|
||||
{
|
||||
// particle.position += particle.velocity * dt;
|
||||
|
||||
// particle.lifetime -= dt;
|
||||
// particle.size -= 1.2f * dt;
|
||||
// particle.color += 1.0f * dt;
|
||||
|
||||
if (particle.lifetime < 0.0f || particle.size < 0.0f)
|
||||
if (particle.life < 0.0f || particle.scaleAndDecay.x < 0.0f || particle.scaleAndDecay.y < 0.0f)
|
||||
{
|
||||
particle.lifetime = 0.0f;
|
||||
particle.life = 0.0f;
|
||||
particle.position.x = 99999.0f;
|
||||
|
||||
outputParticles.data[index] = particle;
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
|||
Name: ParticleUpdate_CS
|
||||
ID: 36260925
|
||||
Type: 2
|
|
@ -0,0 +1,15 @@
|
|||
#version 460 core
|
||||
|
||||
layout (location = 0) out vec4 fragColor;
|
||||
|
||||
// between shader stages
|
||||
layout(location = 0) in struct
|
||||
{
|
||||
vec2 uv; // location = 0
|
||||
|
||||
} In;
|
||||
|
||||
void main ()
|
||||
{
|
||||
fragColor = vec4 (1.0f);
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
|||
Name: Particle_FS
|
||||
ID: 42509714
|
||||
Type: 2
|
|
@ -0,0 +1,93 @@
|
|||
#version 460 core
|
||||
|
||||
struct GenericData
|
||||
{
|
||||
//! Delta time
|
||||
float dt;
|
||||
|
||||
//! Elapsed time of the application
|
||||
float elapsedTime;
|
||||
|
||||
//! Viewport width of the scene (excluding imgui, that means smaller than window)
|
||||
uint viewportWidth;
|
||||
|
||||
//! Ditto but for height
|
||||
uint viewportHeight;
|
||||
};
|
||||
|
||||
|
||||
struct ParticleData
|
||||
{
|
||||
vec4 position;
|
||||
vec4 rotation;
|
||||
vec4 velocity;
|
||||
vec4 acceleration;
|
||||
vec4 scaleAndDecay;
|
||||
float life;
|
||||
uint textureIndex;
|
||||
};
|
||||
|
||||
layout (set = 0, binding = 0) uniform GenericDataBuffer
|
||||
{
|
||||
GenericData data;
|
||||
} genericDataBuffer;
|
||||
|
||||
|
||||
layout(set = 1, binding = 0) uniform CameraData
|
||||
{
|
||||
vec4 position;
|
||||
mat4 vpMat;
|
||||
mat4 viewMat;
|
||||
mat4 projMat;
|
||||
} cameraData;
|
||||
|
||||
// output buffer not needed
|
||||
layout (std430, set = 2, binding = 2) coherent restrict buffer ParticlesOutputBuffer
|
||||
{
|
||||
ParticleData data[];
|
||||
} outputParticles;
|
||||
|
||||
layout (std430, set = 2, binding = 4) coherent restrict buffer IndicesData
|
||||
{
|
||||
uint indices[];
|
||||
};
|
||||
|
||||
// between shader stages
|
||||
layout(location = 0) out struct
|
||||
{
|
||||
vec2 uv; // location = 0
|
||||
|
||||
} Out;
|
||||
|
||||
vec2 CreateQuad (in uint vertexID)
|
||||
{
|
||||
uint b = 1 << vertexID;
|
||||
return vec2 ((0x3 & b) != 0, (0x9 & b) != 0);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
// Create a quad and its texture coordinates
|
||||
Out.uv = CreateQuad (gl_VertexIndex);
|
||||
vec3 vertexPos = vec3 (Out.uv - vec2(0.5f), 0.0f);
|
||||
|
||||
ParticleData particle = outputParticles.data[indices[gl_InstanceIndex]];
|
||||
|
||||
vec3 normalized = normalize (particle.velocity.xyz);
|
||||
float angle = atan (normalized.y, normalized.x);
|
||||
vec2 particleScaleData = particle.scaleAndDecay.xz; // x and y
|
||||
|
||||
mat4 localModel = mat4 (1.0f);
|
||||
localModel[0][0] = particleScaleData.x;
|
||||
localModel[1][1] = particleScaleData.y;
|
||||
|
||||
mat4 rotate = mat4(1.0f);
|
||||
rotate[0][0] = cos(angle);
|
||||
rotate[0][1] = sin(angle);
|
||||
rotate[1][0] = -sin(angle);
|
||||
rotate[1][1] = cos(angle);
|
||||
localModel = rotate * localModel;
|
||||
|
||||
localModel[3] = vec4 (particle.position.xyz, 1.0f);
|
||||
gl_Position = cameraData.vpMat * localModel * vec4(vertexPos, 1.0f);
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
|||
Name: Particle_VS
|
||||
ID: 35035037
|
||||
Type: 2
|
|
@ -30,6 +30,7 @@
|
|||
#include "../SHEditorWindowManager.h"
|
||||
#include "../AssetBrowser/SHAssetBrowser.h"
|
||||
#include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h"
|
||||
#include "Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h"
|
||||
#include "Animation/SHAnimationClip.h"
|
||||
|
||||
namespace SHADE
|
||||
|
@ -804,4 +805,32 @@ namespace SHADE
|
|||
ImGui::PopID();
|
||||
}
|
||||
|
||||
template<>
|
||||
static void DrawComponent(SHParticleEmitterComponent* component)
|
||||
{
|
||||
if (!component)
|
||||
return;
|
||||
|
||||
ImGui::PushID(SHFamilyID<SHComponent>::GetID<SHParticleEmitterComponent>());
|
||||
|
||||
const auto componentType = rttr::type::get(*component);
|
||||
|
||||
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::CollapsingHeader(componentType.get_name().data(), ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
DrawContextMenu(component);
|
||||
|
||||
SHEditorWidgets::DragFloat("Emission Count", [comp = component]() {return comp->GetEmissionCount(); }, [comp = component](float count) {comp->SetEmissionCount(count);});
|
||||
SHEditorWidgets::CheckBox("Is Passive", [comp = component]() {return comp->GetPassive(); }, [comp = component](bool flag) {comp->SetPassive(flag); });
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawContextMenu(component);
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -450,7 +450,7 @@ namespace SHADE
|
|||
*/
|
||||
/***************************************************************************/
|
||||
|
||||
void SHVkCommandBuffer::DrawMultiIndirect(Handle<SHVkBuffer> indirectDrawData, uint32_t drawCount)
|
||||
void SHVkCommandBuffer::DrawMultiIndirectIndexed(Handle<SHVkBuffer> indirectDrawData, uint32_t drawCount)
|
||||
{
|
||||
if (cmdBufferState != SH_CMD_BUFFER_STATE::RECORDING)
|
||||
{
|
||||
|
@ -462,6 +462,19 @@ namespace SHADE
|
|||
vkCommandBuffer.drawIndexedIndirect(indirectDrawData->GetVkBuffer(), 0, drawCount, sizeof(vk::DrawIndexedIndirectCommand));
|
||||
}
|
||||
|
||||
void SHVkCommandBuffer::DrawMultiIndirect(Handle<SHVkBuffer> indirectDrawData, uint32_t drawCount)
|
||||
{
|
||||
if (cmdBufferState != SH_CMD_BUFFER_STATE::RECORDING)
|
||||
{
|
||||
SHLOG_ERROR("Command buffer must have started recording before a pipeline can be bound.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (indirectDrawData)
|
||||
vkCommandBuffer.drawIndirect(indirectDrawData->GetVkBuffer(), 0, drawCount, sizeof(vk::DrawIndexedIndirectCommand));
|
||||
|
||||
}
|
||||
|
||||
void SHVkCommandBuffer::ComputeDispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept
|
||||
{
|
||||
vkCommandBuffer.dispatch (groupCountX, groupCountY, groupCountZ);
|
||||
|
|
|
@ -130,6 +130,7 @@ namespace SHADE
|
|||
// Draw Commands
|
||||
void DrawArrays (uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) const noexcept;
|
||||
void DrawIndexed (uint32_t indexCount, uint32_t firstIndex, uint32_t vertexOffset) const noexcept;
|
||||
void DrawMultiIndirectIndexed (Handle<SHVkBuffer> indirectDrawData, uint32_t drawCount);
|
||||
void DrawMultiIndirect (Handle<SHVkBuffer> indirectDrawData, uint32_t drawCount);
|
||||
|
||||
// Compute Commands
|
||||
|
|
|
@ -755,7 +755,7 @@ namespace SHADE
|
|||
}
|
||||
|
||||
}
|
||||
cmdBuffer->DrawMultiIndirect(drawDataBuffer[frameIndex], static_cast<uint32_t>(drawData.size()));
|
||||
cmdBuffer->DrawMultiIndirectIndexed(drawDataBuffer[frameIndex], static_cast<uint32_t>(drawData.size()));
|
||||
cmdBuffer->EndLabeledSegment();
|
||||
}
|
||||
|
||||
|
|
|
@ -251,7 +251,7 @@ namespace SHADE
|
|||
// particle draw call binding
|
||||
SHVkDescriptorSetLayout::Binding particleDrawDataBinding
|
||||
{
|
||||
.Type = vk::DescriptorType::eUniformBufferDynamic, // UBO (Because lesser data), dynamic (1 set for each frame)
|
||||
.Type = vk::DescriptorType::eStorageBufferDynamic, // UBO (Because lesser data), dynamic (1 set for each frame)
|
||||
.Stage = vk::ShaderStageFlagBits::eCompute,
|
||||
.BindPoint = SHGraphicsConstants::DescriptorSetBindings::PARTICLE_DRAW_DATA,
|
||||
.DescriptorCount = 1,
|
||||
|
|
|
@ -730,7 +730,7 @@ namespace SHADE
|
|||
cmdBuffer->BindVertexBuffer(COLOR_BIND_PT, batch.InstanceColorBuffer[frameIndex], 0);
|
||||
|
||||
// Execute draw
|
||||
cmdBuffer->DrawMultiIndirect(batch.MDIBuffer[frameIndex], static_cast<uint32_t>(batch.MDIData.size()));
|
||||
cmdBuffer->DrawMultiIndirectIndexed(batch.MDIBuffer[frameIndex], static_cast<uint32_t>(batch.MDIData.size()));
|
||||
}
|
||||
|
||||
void SHDebugDrawSystem::destroyBatch(MeshBatch& batch)
|
||||
|
|
|
@ -144,6 +144,10 @@ namespace SHADE
|
|||
//SHAssetManager::CompileAsset("../../Assets/Shaders/Trajectory_FS.glsl", false);
|
||||
//SHAssetManager::CompileAsset("../../Assets/Shaders/ShadowMapBlur_CS.glsl", false);
|
||||
//SHAssetManager::CompileAsset("../../Assets/Shaders/Anim_VS.glsl", false);
|
||||
SHAssetManager::CompileAsset("../../Assets/Shaders/Particle_VS.glsl", false);
|
||||
SHAssetManager::CompileAsset("../../Assets/Shaders/Particle_FS.glsl", false);
|
||||
SHAssetManager::CompileAsset("../../Assets/Shaders/ParticleEmit_CS.glsl", false);
|
||||
SHAssetManager::CompileAsset("../../Assets/Shaders/ParticleUpdate_CS.glsl", false);
|
||||
|
||||
// Load Built In Shaders
|
||||
static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(VS_DEFAULT);
|
||||
|
@ -165,6 +169,9 @@ namespace SHADE
|
|||
static constexpr AssetID TRAJECTORY_VS = 41042628; trajectoryVS = SHResourceManager::LoadOrGet<SHVkShaderModule>(TRAJECTORY_VS);
|
||||
static constexpr AssetID TRAJECTORY_FS = 45635685; trajectoryFS = SHResourceManager::LoadOrGet<SHVkShaderModule>(TRAJECTORY_FS);
|
||||
static constexpr AssetID SHADOW_BLUR_CS = 38004013; shadowMapBlurCS = SHResourceManager::LoadOrGet<SHVkShaderModule>(SHADOW_BLUR_CS);
|
||||
static constexpr AssetID PARTICLE_VS = 35035037; particleVS = SHResourceManager::LoadOrGet<SHVkShaderModule>(PARTICLE_VS);
|
||||
static constexpr AssetID PARTICLE_EMIT_CS = 42509714; particleEmitCS = SHResourceManager::LoadOrGet<SHVkShaderModule>(PARTICLE_EMIT_CS);
|
||||
static constexpr AssetID PARTICLE_UPDATE_CS = 36260925; particleUpdateCS = SHResourceManager::LoadOrGet<SHVkShaderModule>(PARTICLE_UPDATE_CS);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -484,6 +484,10 @@ namespace SHADE
|
|||
Handle<SHVkShaderModule> trajectoryVS;
|
||||
Handle<SHVkShaderModule> trajectoryFS;
|
||||
Handle<SHVkShaderModule> shadowMapBlurCS;
|
||||
Handle<SHVkShaderModule> particleVS;
|
||||
Handle<SHVkShaderModule> particleFS;
|
||||
Handle<SHVkShaderModule> particleEmitCS;
|
||||
Handle<SHVkShaderModule> particleUpdateCS;
|
||||
|
||||
// Fonts
|
||||
Handle<SHFont> testFont;
|
||||
|
|
|
@ -20,4 +20,24 @@ namespace SHADE
|
|||
toEmit = true;
|
||||
}
|
||||
|
||||
void SHParticleEmitterComponent::SetEmissionCount(float count) noexcept
|
||||
{
|
||||
emissionCount = count;
|
||||
}
|
||||
|
||||
bool SHParticleEmitterComponent::SetPassive(bool flag) noexcept
|
||||
{
|
||||
isPassive = flag;
|
||||
}
|
||||
|
||||
float SHParticleEmitterComponent::GetEmissionCount(void) noexcept
|
||||
{
|
||||
return emissionCount;
|
||||
}
|
||||
|
||||
bool SHParticleEmitterComponent::GetPassive(void) noexcept
|
||||
{
|
||||
return isPassive;
|
||||
}
|
||||
|
||||
}
|
|
@ -105,6 +105,12 @@ namespace SHADE
|
|||
|
||||
void Emit (void) noexcept;
|
||||
|
||||
void SetEmissionCount (float count) noexcept;
|
||||
bool SetPassive (bool flag) noexcept;
|
||||
|
||||
float GetEmissionCount (void) noexcept;
|
||||
bool GetPassive (void) noexcept;
|
||||
|
||||
friend class SHParticleSubSystem;
|
||||
|
||||
};
|
||||
|
|
|
@ -60,7 +60,7 @@ namespace SHADE
|
|||
}
|
||||
|
||||
// buffer to store draw call data. Non-indexed, host-visible mapped, triple buffered.
|
||||
comp.drawCallData = logicalDevice->CreateBuffer(SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmd, indirectCommands.data(), SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmd, vk::BufferUsageFlagBits::eUniformBuffer | 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 * sizeofIndirectCmd, indirectCommands.data(), SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmd, 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);
|
||||
|
||||
}
|
||||
|
||||
|
@ -150,6 +150,59 @@ namespace SHADE
|
|||
|
||||
void SHParticleSubSystem::RenderComponent(Handle<SHVkCommandBuffer> cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept
|
||||
{
|
||||
cmdBuffer->DrawMultiIndirect(comp.drawCallData, 1);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
// 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
|
||||
{
|
||||
.srcAccessMask = vk::AccessFlagBits::eShaderWrite,
|
||||
.dstAccessMask = vk::AccessFlagBits::eShaderRead,
|
||||
.buffer = emitter.particleData->GetVkBuffer(),
|
||||
.offset = emitter.dynamicOffsets[FRAME_INDEX][DYOFF_INDEX_PARTICLE_INPUT],
|
||||
.size = emitter.chunkSize
|
||||
};
|
||||
|
||||
// pre-update free list data barrier
|
||||
vk::BufferMemoryBarrier freelistDataBarrier
|
||||
{
|
||||
.srcAccessMask = vk::AccessFlagBits::eShaderWrite,
|
||||
.dstAccessMask = vk::AccessFlagBits::eShaderRead,
|
||||
.buffer = emitter.freelistData->GetVkBuffer(),
|
||||
.offset = 0, // Only 1 copy of freelist data, so offset is at 0
|
||||
.size = static_cast<uint32_t>(sizeof (uint32_t)) * (emitter.maxParticles + 1)
|
||||
};
|
||||
|
||||
// ...copy assign barriers on heap
|
||||
preUpdateBarriers[EMITTER_INDEX * 2] = particleDataBarrier;
|
||||
preUpdateBarriers[(EMITTER_INDEX * 2) + 1] = freelistDataBarrier;
|
||||
|
||||
// make new barrier on stack...
|
||||
vk::BufferMemoryBarrier particleDataBarrierPost
|
||||
{
|
||||
.srcAccessMask = vk::AccessFlagBits::eShaderWrite,
|
||||
.dstAccessMask = vk::AccessFlagBits::eShaderRead,
|
||||
.buffer = emitter.particleData->GetVkBuffer(),
|
||||
.offset = emitter.dynamicOffsets[FRAME_INDEX][DYOFF_INDEX_PARTICLE_OUTPUT],
|
||||
.size = emitter.chunkSize
|
||||
};
|
||||
|
||||
// make new barrier on stack...
|
||||
vk::BufferMemoryBarrier indicesDataBarrier
|
||||
{
|
||||
.srcAccessMask = vk::AccessFlagBits::eShaderWrite,
|
||||
.dstAccessMask = vk::AccessFlagBits::eShaderRead,
|
||||
.buffer = emitter.indicesData->GetVkBuffer(),
|
||||
.offset = emitter.dynamicOffsets[FRAME_INDEX][DYOFF_INDEX_INDICES_DATA],
|
||||
.size = static_cast<uint32_t>(sizeof(uint32_t)) * emitter.maxParticles
|
||||
};
|
||||
|
||||
|
||||
// ...copy assign barriers on heap
|
||||
postUpdateBarriers[EMITTER_INDEX * 2] = particleDataBarrierPost;
|
||||
postUpdateBarriers[(EMITTER_INDEX * 2) + 1] = indicesDataBarrier;
|
||||
|
||||
}
|
||||
|
||||
|
@ -203,10 +256,19 @@ namespace SHADE
|
|||
// Get offset into GPU emitter data (for updating)
|
||||
uint32_t emitterDataOffset = frameIndex * sizeof (SHParticleEmitterComponent::GPUEmitterStruct);
|
||||
|
||||
// TODO: OPTIONAL but eventually these barriers can be moved to the system as member variables. This would require additional bookkeeping
|
||||
// but it will be more efficient than populating a vector every frame.
|
||||
|
||||
// Barriers to make sure emitting shader is done completely before update is run.
|
||||
// Every emitter will have its own barrier.
|
||||
// Every emitter will have its own barrier for its particle data and freelist data. Indices data is not needed since
|
||||
// it's mainly used in update and rendering so a barrier for it is NOT needed here.
|
||||
std::vector<vk::BufferMemoryBarrier> preUpdateBarriers{};
|
||||
preUpdateBarriers.resize(emitters.size());
|
||||
preUpdateBarriers.resize(emitters.size() * 2);
|
||||
|
||||
// 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() * 2);
|
||||
|
||||
// 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.
|
||||
|
@ -255,19 +317,10 @@ namespace SHADE
|
|||
EmitComponent(cmdBuffer, emitter, frameIndex);
|
||||
}
|
||||
|
||||
// make new barrier on stack...
|
||||
vk::BufferMemoryBarrier barrier
|
||||
{
|
||||
.srcAccessMask = vk::AccessFlagBits::eShaderWrite,
|
||||
.dstAccessMask = vk::AccessFlagBits::eShaderRead,
|
||||
.buffer = emitter.particleData->GetVkBuffer(),
|
||||
.offset = emitter.dynamicOffsets[frameIndex][DYOFF_INDEX_PARTICLE_INPUT],
|
||||
.size = emitter.chunkSize
|
||||
};
|
||||
|
||||
// ...copy assign barrier on heap
|
||||
preUpdateBarriers[i] = barrier;
|
||||
// prepare barriers
|
||||
PreparePrePostUpdateBarriers(preUpdateBarriers, postUpdateBarriers, emitter, i, frameIndex);
|
||||
|
||||
// Emitter will emit once and stop emitting next frame (unless specified before reaching here to do so).
|
||||
emitter.toEmit = false;
|
||||
++i;
|
||||
}
|
||||
|
@ -275,6 +328,8 @@ namespace SHADE
|
|||
// issue the barrier to wait
|
||||
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {}, preUpdateBarriers, {});
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* EMITTING PARTICLES DONE, BEGIN UPDATES.... */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
@ -287,6 +342,11 @@ namespace SHADE
|
|||
UpdateCompoennt(cmdBuffer, emitter, frameIndex);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* AFTER UPDATING, RENDER PARTICLES */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
// 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, {});
|
||||
|
||||
}
|
||||
|
||||
|
@ -297,7 +357,7 @@ namespace SHADE
|
|||
// TODO: Issue barrier for output particle data. Semaphore should also be issued outside in SHGraphicsSystem
|
||||
for (auto& emitter : emitters)
|
||||
{
|
||||
|
||||
RenderComponent(cmdBuffer, emitter, frameIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -81,6 +81,8 @@ 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;
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -198,7 +198,7 @@ namespace SHADE
|
|||
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRAJECTORY_TRANSFORM, transformBuffer, 0);
|
||||
|
||||
// call draw call
|
||||
cmdBuffer->DrawMultiIndirect(drawDataBuffer, drawData.size());
|
||||
cmdBuffer->DrawMultiIndirectIndexed(drawDataBuffer, drawData.size());
|
||||
|
||||
// clear CPU transform and draw data
|
||||
transformData.clear();
|
||||
|
|
Loading…
Reference in New Issue