Particles WIP
This commit is contained in:
parent
eeaa642f30
commit
2f4a316a09
|
@ -7,7 +7,7 @@ struct EmitterParameters
|
||||||
vec4 angularMin;
|
vec4 angularMin;
|
||||||
vec4 angularMax;
|
vec4 angularMax;
|
||||||
vec4 lifeAndSizeRange; // min life, max life, min size, max size
|
vec4 lifeAndSizeRange; // min life, max life, min size, max size
|
||||||
}
|
};
|
||||||
|
|
||||||
struct ParticleData
|
struct ParticleData
|
||||||
{
|
{
|
||||||
|
@ -18,7 +18,7 @@ struct ParticleData
|
||||||
vec4 scaleAndDecay;
|
vec4 scaleAndDecay;
|
||||||
float life;
|
float life;
|
||||||
uint textureIndex;
|
uint textureIndex;
|
||||||
}
|
};
|
||||||
|
|
||||||
struct GenericData
|
struct GenericData
|
||||||
{
|
{
|
||||||
|
@ -96,9 +96,15 @@ float rand(inout uint state)
|
||||||
return float(x)*uintBitsToFloat(0x2f800004u);
|
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()
|
void main()
|
||||||
{
|
{
|
||||||
uint emitterInvocationIndex = gl_GlobalInvocationID.x;
|
uint emitterInvocationIndex = gl_GlobalInvocationID.x;
|
||||||
|
vec4 emitterPosition = emitterPushConstant.emitterPosition;
|
||||||
|
|
||||||
if (emitterInvocationIndex >= emitterPushConstant.emissionCount)
|
if (emitterInvocationIndex >= emitterPushConstant.emissionCount)
|
||||||
return;
|
return;
|
||||||
|
@ -109,9 +115,18 @@ void main()
|
||||||
|
|
||||||
ParticleData particle;
|
ParticleData particle;
|
||||||
|
|
||||||
int index = freelist.freeIndices[freelistIndex];
|
// Get seed for randomization
|
||||||
particle.position = emitterPosition;
|
uint pixel_index = uint (emitterPosition.x + emitterPosition.y + floatBitsToUint(genericDataBuffer.data.elapsedTime) * (gl_GlobalInvocationID.x + 1));
|
||||||
particle.life = emitterParams.10.0f;
|
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;
|
vec4 scaleAndDecay;
|
||||||
float life;
|
float life;
|
||||||
uint textureIndex;
|
uint textureIndex;
|
||||||
}
|
};
|
||||||
|
|
||||||
struct GenericData
|
struct GenericData
|
||||||
{
|
{
|
||||||
|
@ -73,7 +73,7 @@ layout (std430, set = 2, binding = 4) coherent restrict buffer IndicesData
|
||||||
uint indices[];
|
uint indices[];
|
||||||
};
|
};
|
||||||
|
|
||||||
layout (std140, set = 2, binding = 5) coherent restrict uniform IndirectDrawArgs
|
layout (std140, set = 2, binding = 5) coherent restrict buffer IndirectDrawArgs
|
||||||
{
|
{
|
||||||
DrawArraysIndirectArgs indirectArgs;
|
DrawArraysIndirectArgs indirectArgs;
|
||||||
};
|
};
|
||||||
|
@ -116,17 +116,12 @@ void main()
|
||||||
|
|
||||||
ParticleData particle = inputParticles.data[index];
|
ParticleData particle = inputParticles.data[index];
|
||||||
|
|
||||||
if (particle.lifetime > 0.0f)
|
if (particle.life > 0.0f)
|
||||||
{
|
{
|
||||||
// particle.position += particle.velocity * dt;
|
|
||||||
|
|
||||||
// particle.lifetime -= dt;
|
if (particle.life < 0.0f || particle.scaleAndDecay.x < 0.0f || particle.scaleAndDecay.y < 0.0f)
|
||||||
// particle.size -= 1.2f * dt;
|
|
||||||
// particle.color += 1.0f * dt;
|
|
||||||
|
|
||||||
if (particle.lifetime < 0.0f || particle.size < 0.0f)
|
|
||||||
{
|
{
|
||||||
particle.lifetime = 0.0f;
|
particle.life = 0.0f;
|
||||||
particle.position.x = 99999.0f;
|
particle.position.x = 99999.0f;
|
||||||
|
|
||||||
outputParticles.data[index] = particle;
|
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 "../SHEditorWindowManager.h"
|
||||||
#include "../AssetBrowser/SHAssetBrowser.h"
|
#include "../AssetBrowser/SHAssetBrowser.h"
|
||||||
#include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h"
|
#include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h"
|
||||||
|
#include "Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h"
|
||||||
#include "Animation/SHAnimationClip.h"
|
#include "Animation/SHAnimationClip.h"
|
||||||
|
|
||||||
namespace SHADE
|
namespace SHADE
|
||||||
|
@ -804,4 +805,32 @@ namespace SHADE
|
||||||
ImGui::PopID();
|
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)
|
if (cmdBufferState != SH_CMD_BUFFER_STATE::RECORDING)
|
||||||
{
|
{
|
||||||
|
@ -462,6 +462,19 @@ namespace SHADE
|
||||||
vkCommandBuffer.drawIndexedIndirect(indirectDrawData->GetVkBuffer(), 0, drawCount, sizeof(vk::DrawIndexedIndirectCommand));
|
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
|
void SHVkCommandBuffer::ComputeDispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept
|
||||||
{
|
{
|
||||||
vkCommandBuffer.dispatch (groupCountX, groupCountY, groupCountZ);
|
vkCommandBuffer.dispatch (groupCountX, groupCountY, groupCountZ);
|
||||||
|
|
|
@ -130,6 +130,7 @@ namespace SHADE
|
||||||
// Draw Commands
|
// Draw Commands
|
||||||
void DrawArrays (uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) const noexcept;
|
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 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);
|
void DrawMultiIndirect (Handle<SHVkBuffer> indirectDrawData, uint32_t drawCount);
|
||||||
|
|
||||||
// Compute Commands
|
// 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();
|
cmdBuffer->EndLabeledSegment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -251,7 +251,7 @@ namespace SHADE
|
||||||
// particle draw call binding
|
// particle draw call binding
|
||||||
SHVkDescriptorSetLayout::Binding particleDrawDataBinding
|
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,
|
.Stage = vk::ShaderStageFlagBits::eCompute,
|
||||||
.BindPoint = SHGraphicsConstants::DescriptorSetBindings::PARTICLE_DRAW_DATA,
|
.BindPoint = SHGraphicsConstants::DescriptorSetBindings::PARTICLE_DRAW_DATA,
|
||||||
.DescriptorCount = 1,
|
.DescriptorCount = 1,
|
||||||
|
|
|
@ -730,7 +730,7 @@ namespace SHADE
|
||||||
cmdBuffer->BindVertexBuffer(COLOR_BIND_PT, batch.InstanceColorBuffer[frameIndex], 0);
|
cmdBuffer->BindVertexBuffer(COLOR_BIND_PT, batch.InstanceColorBuffer[frameIndex], 0);
|
||||||
|
|
||||||
// Execute draw
|
// 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)
|
void SHDebugDrawSystem::destroyBatch(MeshBatch& batch)
|
||||||
|
|
|
@ -144,6 +144,10 @@ namespace SHADE
|
||||||
//SHAssetManager::CompileAsset("../../Assets/Shaders/Trajectory_FS.glsl", false);
|
//SHAssetManager::CompileAsset("../../Assets/Shaders/Trajectory_FS.glsl", false);
|
||||||
//SHAssetManager::CompileAsset("../../Assets/Shaders/ShadowMapBlur_CS.glsl", false);
|
//SHAssetManager::CompileAsset("../../Assets/Shaders/ShadowMapBlur_CS.glsl", false);
|
||||||
//SHAssetManager::CompileAsset("../../Assets/Shaders/Anim_VS.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
|
// Load Built In Shaders
|
||||||
static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(VS_DEFAULT);
|
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_VS = 41042628; trajectoryVS = SHResourceManager::LoadOrGet<SHVkShaderModule>(TRAJECTORY_VS);
|
||||||
static constexpr AssetID TRAJECTORY_FS = 45635685; trajectoryFS = SHResourceManager::LoadOrGet<SHVkShaderModule>(TRAJECTORY_FS);
|
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 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> trajectoryVS;
|
||||||
Handle<SHVkShaderModule> trajectoryFS;
|
Handle<SHVkShaderModule> trajectoryFS;
|
||||||
Handle<SHVkShaderModule> shadowMapBlurCS;
|
Handle<SHVkShaderModule> shadowMapBlurCS;
|
||||||
|
Handle<SHVkShaderModule> particleVS;
|
||||||
|
Handle<SHVkShaderModule> particleFS;
|
||||||
|
Handle<SHVkShaderModule> particleEmitCS;
|
||||||
|
Handle<SHVkShaderModule> particleUpdateCS;
|
||||||
|
|
||||||
// Fonts
|
// Fonts
|
||||||
Handle<SHFont> testFont;
|
Handle<SHFont> testFont;
|
||||||
|
|
|
@ -20,4 +20,24 @@ namespace SHADE
|
||||||
toEmit = true;
|
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 Emit (void) noexcept;
|
||||||
|
|
||||||
|
void SetEmissionCount (float count) noexcept;
|
||||||
|
bool SetPassive (bool flag) noexcept;
|
||||||
|
|
||||||
|
float GetEmissionCount (void) noexcept;
|
||||||
|
bool GetPassive (void) noexcept;
|
||||||
|
|
||||||
friend class SHParticleSubSystem;
|
friend class SHParticleSubSystem;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -60,7 +60,7 @@ namespace SHADE
|
||||||
}
|
}
|
||||||
|
|
||||||
// buffer to store draw call data. Non-indexed, host-visible mapped, triple buffered.
|
// 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
|
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)
|
// Get offset into GPU emitter data (for updating)
|
||||||
uint32_t emitterDataOffset = frameIndex * sizeof (SHParticleEmitterComponent::GPUEmitterStruct);
|
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.
|
// 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{};
|
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
|
// 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.
|
// 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);
|
EmitComponent(cmdBuffer, emitter, frameIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// make new barrier on stack...
|
// prepare barriers
|
||||||
vk::BufferMemoryBarrier barrier
|
PreparePrePostUpdateBarriers(preUpdateBarriers, postUpdateBarriers, emitter, i, frameIndex);
|
||||||
{
|
|
||||||
.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;
|
|
||||||
|
|
||||||
|
// Emitter will emit once and stop emitting next frame (unless specified before reaching here to do so).
|
||||||
emitter.toEmit = false;
|
emitter.toEmit = false;
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
@ -275,6 +328,8 @@ namespace SHADE
|
||||||
// issue the barrier to wait
|
// issue the barrier to wait
|
||||||
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {}, preUpdateBarriers, {});
|
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {}, preUpdateBarriers, {});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
/* EMITTING PARTICLES DONE, BEGIN UPDATES.... */
|
/* EMITTING PARTICLES DONE, BEGIN UPDATES.... */
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
|
@ -287,6 +342,11 @@ namespace SHADE
|
||||||
UpdateCompoennt(cmdBuffer, emitter, frameIndex);
|
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
|
// TODO: Issue barrier for output particle data. Semaphore should also be issued outside in SHGraphicsSystem
|
||||||
for (auto& emitter : emitters)
|
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 UpdateCompoennt(Handle<SHVkCommandBuffer> cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept;
|
||||||
void RenderComponent(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:
|
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 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);
|
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRAJECTORY_TRANSFORM, transformBuffer, 0);
|
||||||
|
|
||||||
// call draw call
|
// call draw call
|
||||||
cmdBuffer->DrawMultiIndirect(drawDataBuffer, drawData.size());
|
cmdBuffer->DrawMultiIndirectIndexed(drawDataBuffer, drawData.size());
|
||||||
|
|
||||||
// clear CPU transform and draw data
|
// clear CPU transform and draw data
|
||||||
transformData.clear();
|
transformData.clear();
|
||||||
|
|
Loading…
Reference in New Issue