diff --git a/Assets/Shaders/ParticleEmit_CS.glsl b/Assets/Shaders/ParticleEmit_CS.glsl new file mode 100644 index 00000000..421e2ce1 --- /dev/null +++ b/Assets/Shaders/ParticleEmit_CS.glsl @@ -0,0 +1,117 @@ +#version 450 + +layout(local_size_x = 128) in; + +struct EmitterParameters +{ + vec4 angularMin; + vec4 angularMax; + vec4 lifeAndSizeRange; // min life, max life, min size, max size +} + +struct ParticleData +{ + vec4 position; + vec4 rotation; + vec4 velocity; + vec4 acceleration; + vec4 scaleAndDecay; + float life; + uint textureIndex; +} + +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; +}; + +layout (set = 0, binding = 0) uniform GenericDataBuffer +{ + GenericData data; +} genericDataBuffer; + +layout (std430, set = 2, binding = 0) readonly buffer EmitterBuffer +{ + EmitterParameters data; +} emitterParams; + +layout (std430, set = 2, binding = 1) coherent restrict buffer ParticlesInputBuffer +{ + ParticleData data[]; +} inputParticles; + +// output buffer not needed +// layout (std430, set = 2, binding = 2) coherent restrict buffer ParticlesOutputBuffer +// { +// ParticleData data[]; +// } outputParticles; + +layout (std430, set = 2, binding = 3) coherent restrict buffer ParticlesFreelistBuffer +{ + int freeCount; + int freeIndices[]; + +} freelist; + + +// push constants +layout(std140, push_constant) uniform EmitterPushConstant +{ + vec4 emitterPosition; + uint emissionCount; + +} emitterPushConstant; + +uint pcg_hash(uint seed) +{ + uint state = seed * 747796405u + 2891336453u; + uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + return (word >> 22u) ^ word; +} + +// Used to advance the PCG state. +uint rand_pcg(inout uint rng_state) +{ + uint state = rng_state; + rng_state = rng_state * 747796405u + 2891336453u; + uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + return (word >> 22u) ^ word; +} + +// Advances the prng state and returns the corresponding random float. +float rand(inout uint state) +{ + uint x = rand_pcg(state); + state = x; + return float(x)*uintBitsToFloat(0x2f800004u); +} + +void main() +{ + uint emitterInvocationIndex = gl_GlobalInvocationID.x; + + if (emitterInvocationIndex >= emitterPushConstant.emissionCount) + return; + + int freelistIndex = atomicAdd (freelist.freeCount, -1) - 1; + if (freelistIndex < 0) + atomicAdd (freelist.freeCount, 1); + + ParticleData particle; + + int index = freelist.freeIndices[freelistIndex]; + particle.position = emitterPosition; + particle.life = emitterParams.10.0f; + + particles[index] = particle; +} \ No newline at end of file diff --git a/Assets/Shaders/ParticleUpdate_CS.glsl b/Assets/Shaders/ParticleUpdate_CS.glsl new file mode 100644 index 00000000..7649ee63 --- /dev/null +++ b/Assets/Shaders/ParticleUpdate_CS.glsl @@ -0,0 +1,141 @@ +#version 450 + +layout(local_size_x = 128) in; + +struct DrawArraysIndirectArgs +{ + uint count; + uint instanceCount; + uint first; + uint baseInstance; +}; + +struct ParticleData +{ + vec4 position; + vec4 rotation; + vec4 velocity; + vec4 acceleration; + vec4 scaleAndDecay; + float life; + uint textureIndex; +} + +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; +}; + +layout(set = 1, binding = 0) uniform CameraData +{ + vec4 position; + mat4 vpMat; + mat4 viewMat; + mat4 projMat; +} cameraData; + + +layout (set = 0, binding = 0) uniform GenericDataBuffer +{ + GenericData data; +} genericDataBuffer; + +layout (std430, set = 2, binding = 1) coherent restrict readonly buffer ParticlesInputBuffer +{ + ParticleData data[]; +} inputParticles; + +// output buffer not needed +layout (std430, set = 2, binding = 2) coherent restrict buffer ParticlesOutputBuffer +{ + ParticleData data[]; +} outputParticles; + +layout (std430, set = 2, binding = 3) coherent restrict buffer ParticlesFreelistBuffer +{ + int freeCount; + int freeIndices[]; + +} freelist; + +layout (std430, set = 2, binding = 4) coherent restrict buffer IndicesData +{ + uint indices[]; +}; + +layout (std140, set = 2, binding = 5) coherent restrict uniform IndirectDrawArgs +{ + DrawArraysIndirectArgs indirectArgs; +}; + +// push constants +layout(std140, push_constant) uniform EmitterPushConstant +{ + vec4 emitterPosition; + uint emissionCount; + +} emitterPushConstant; + +uint pcg_hash(uint seed) +{ + uint state = seed * 747796405u + 2891336453u; + uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + return (word >> 22u) ^ word; +} + +// Used to advance the PCG state. +uint rand_pcg(inout uint rng_state) +{ + uint state = rng_state; + rng_state = rng_state * 747796405u + 2891336453u; + uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + return (word >> 22u) ^ word; +} + +// Advances the prng state and returns the corresponding random float. +float rand(inout uint state) +{ + uint x = rand_pcg(state); + state = x; + return float(x)*uintBitsToFloat(0x2f800004u); +} + +void main() +{ + uint index = gl_GlobalInvocationID.x; + + ParticleData particle = inputParticles.data[index]; + + if (particle.lifetime > 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) + { + particle.lifetime = 0.0f; + particle.position.x = 99999.0f; + + outputParticles.data[index] = particle; + freelist.freeIndices[atomicAdd(freelist.freeCount, 1)] = int (index); + return; + } + + outputParticles.data[index] = particle; + uint drawIndex = atomicAdd (indirectArgs.instanceCount, 1); + indices[drawIndex] = index; + } +} \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 9e86f7bf..af03ffa6 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -600,7 +600,7 @@ namespace SHADE } ); - SHEditorWidgets::ColorPicker("Color", [&textComp = component]() {return textComp->GetColour(); }, [&textComp = component](SHVec4 const& newColor) {textComp->SetColour(newColor); }); + SHEditorWidgets::ColorPicker("Color", [&textComp = component]() {return textComp->GetColor(); }, [&textComp = component](SHVec4 const& newColor) {textComp->SetColor(newColor); }); } else { diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp index c95221ec..faede2bd 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp @@ -180,6 +180,10 @@ namespace SHADE { DrawComponent(listenerComponent); } + if (auto trajectoryComponent = SHComponentManager::GetComponent_s(eid)) + { + DrawComponent(trajectoryComponent); + } ImGui::Separator(); // Render Scripts SHScriptEngine* scriptEngine = static_cast(SHSystemManager::GetSystem()); @@ -195,6 +199,7 @@ namespace SHADE DrawAddComponentButton(eid); DrawAddComponentButton(eid); DrawAddComponentButton(eid); + DrawAddComponentButton(eid); // Components that require Transforms diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp index 85559bc7..a15687cb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp @@ -59,6 +59,13 @@ namespace SHADE {SHPredefinedDescriptorTypes::STATIC_DATA, 0}, {SHPredefinedDescriptorTypes::CAMERA, 1}, }); + + perSystemData[SHUtilities::ConvertEnum(SystemType::PARTICLE_RENEDERING)].descMappings.AddMappings + ({ + {SHPredefinedDescriptorTypes::STATIC_DATA, 0}, + {SHPredefinedDescriptorTypes::CAMERA, 1}, + {SHPredefinedDescriptorTypes::PARTICLES, 2}, + }); } void SHGraphicsPredefinedData::InitDummyPipelineLayouts(Handle logicalDevice) noexcept @@ -194,6 +201,73 @@ namespace SHADE Handle materialBoneDataPerInstanceLayout = logicalDevice->CreateDescriptorSetLayout({ materialDataBinding, boneDataBinding }); SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSetLayout, materialBoneDataPerInstanceLayout->GetVkHandle(), "[Descriptor Set Layout] Material and Bone Globals"); + // particle emitter binding + SHVkDescriptorSetLayout::Binding emitterDataBinding + { + .Type = vk::DescriptorType::eStorageBufferDynamic, + .Stage = vk::ShaderStageFlagBits::eCompute, + .BindPoint = SHGraphicsConstants::DescriptorSetBindings::PARTICLE_EMITTER_DATA, + .DescriptorCount = 1, + }; + + // particle input binding + SHVkDescriptorSetLayout::Binding particleInputDataBinding + { + .Type = vk::DescriptorType::eStorageBufferDynamic, + .Stage = vk::ShaderStageFlagBits::eCompute, + .BindPoint = SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INPUT_DATA, + .DescriptorCount = 1, + }; + + // particle output binding + SHVkDescriptorSetLayout::Binding particleOutputDataBinding + { + .Type = vk::DescriptorType::eStorageBufferDynamic, + .Stage = vk::ShaderStageFlagBits::eCompute | vk::ShaderStageFlagBits::eVertex, + .BindPoint = SHGraphicsConstants::DescriptorSetBindings::PARTICLE_OUTPUT_DATA, + .DescriptorCount = 1, + }; + + // particle freelist binding + SHVkDescriptorSetLayout::Binding particleFreelistBinding + { + .Type = vk::DescriptorType::eStorageBuffer, // non dynamic because we only need 1 copy for all frames + .Stage = vk::ShaderStageFlagBits::eCompute, + .BindPoint = SHGraphicsConstants::DescriptorSetBindings::PARTICLE_FREELIST_DATA, + .DescriptorCount = 1, + }; + + // particle indices binding + SHVkDescriptorSetLayout::Binding particleIndicesBinding + { + .Type = vk::DescriptorType::eStorageBufferDynamic, // dynamic because we have multiple copies. + .Stage = vk::ShaderStageFlagBits::eCompute | vk::ShaderStageFlagBits::eVertex, + .BindPoint = SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INDICES_DATA, + .DescriptorCount = 1, + }; + + // particle draw call binding + SHVkDescriptorSetLayout::Binding particleDrawDataBinding + { + .Type = vk::DescriptorType::eUniformBufferDynamic, // UBO (Because lesser data), dynamic (1 set for each frame) + .Stage = vk::ShaderStageFlagBits::eCompute, + .BindPoint = SHGraphicsConstants::DescriptorSetBindings::PARTICLE_DRAW_DATA, + .DescriptorCount = 1, + }; + + Handle particleDescSetLayout = logicalDevice->CreateDescriptorSetLayout( + { + emitterDataBinding, + particleInputDataBinding, + particleOutputDataBinding, + particleFreelistBinding, + particleIndicesBinding, + particleDrawDataBinding + }); + SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSetLayout, particleDescSetLayout->GetVkHandle(), "[Descriptor Set Layout] Particle System Data"); + + + predefinedLayouts.push_back(staticGlobalLayout); predefinedLayouts.push_back(lightDataDescSetLayout); predefinedLayouts.push_back(cameraDataGlobalLayout); @@ -201,6 +275,7 @@ namespace SHADE predefinedLayouts.push_back(fontDataDescSetLayout); predefinedLayouts.push_back(shadowMapDescLayout); predefinedLayouts.push_back(materialBoneDataPerInstanceLayout); + predefinedLayouts.push_back(particleDescSetLayout); perSystemData[SHUtilities::ConvertEnum(SystemType::BATCHING)].descSetLayouts = GetPredefinedDescSetLayouts ( @@ -235,6 +310,13 @@ namespace SHADE SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::STATIC_DATA | SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::CAMERA ); + + perSystemData[SHUtilities::ConvertEnum(SystemType::PARTICLE_RENEDERING)].descSetLayouts = GetPredefinedDescSetLayouts + ( + SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::STATIC_DATA | + SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::CAMERA | + SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::PARTICLES + ); } void SHGraphicsPredefinedData::InitPredefinedVertexInputState(void) noexcept diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h index 77307f57..4fbf06c1 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h @@ -29,7 +29,8 @@ namespace SHADE MATERIALS = 0b00001000, FONT = 0b00010000, SHADOW = 0b00100000, - MATERIAL_AND_BONES = 0b01000000 + MATERIAL_AND_BONES = 0b01000000, + PARTICLES = 0b10000000 }; enum class SystemType @@ -39,6 +40,7 @@ namespace SHADE TEXT_RENDERING, RENDER_GRAPH_NODE_COMPUTE, TRAJECTORY_RENDERING, + PARTICLE_RENEDERING, NUM_TYPES }; static constexpr int SYSTEM_TYPE_COUNT = static_cast(SystemType::NUM_TYPES); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHPredefinedDescriptorTypes.h b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHPredefinedDescriptorTypes.h index 723a3c5a..0b6f0c2f 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHPredefinedDescriptorTypes.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHPredefinedDescriptorTypes.h @@ -16,5 +16,6 @@ namespace SHADE FONT, RENDER_GRAPH_NODE_COMPUTE_RESOURCE, RENDER_GRAPH_RESOURCE, + PARTICLES, }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h index 71d77e2d..468cc0c7 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h @@ -233,6 +233,61 @@ namespace SHADE */ /***************************************************************************/ static constexpr uint32_t BONE_MATRIX_DATA = 1; + + /***************************************************************************/ + /*! + \brief + Descriptor set binding for particle emitter data. + + */ + /***************************************************************************/ + static constexpr uint32_t PARTICLE_EMITTER_DATA = 0; + + /***************************************************************************/ + /*! + \brief + Descriptor set binding for input particle data. + + */ + /***************************************************************************/ + static constexpr uint32_t PARTICLE_INPUT_DATA = 1; + + /***************************************************************************/ + /*! + \brief + Descriptor set binding for output particle data. + + */ + /***************************************************************************/ + static constexpr uint32_t PARTICLE_OUTPUT_DATA = 2; + + /***************************************************************************/ + /*! + \brief + Descriptor set binding for particle freelist data. + + */ + /***************************************************************************/ + static constexpr uint32_t PARTICLE_FREELIST_DATA = 3; + + /***************************************************************************/ + /*! + \brief + Descriptor set binding for particle indices data. + + */ + /***************************************************************************/ + static constexpr uint32_t PARTICLE_INDICES_DATA = 4; + + /***************************************************************************/ + /*! + \brief + Descriptor set binding for bone matrix data. + + */ + /***************************************************************************/ + static constexpr uint32_t PARTICLE_DRAW_DATA = 5; + }; struct VertexBufferBindings diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp new file mode 100644 index 00000000..12690ece --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.cpp @@ -0,0 +1,23 @@ +#include "SHpch.h" +#include "SHParticleEmitterComponent.h" + +namespace SHADE +{ + + void SHParticleEmitterComponent::OnCreate(void) + { + timeBeforeEmission = emissionInterval; + + } + + void SHParticleEmitterComponent::OnDestroy(void) + { + + } + + void SHParticleEmitterComponent::Emit(void) noexcept + { + toEmit = true; + } + +} \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h new file mode 100644 index 00000000..30f7f107 --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h @@ -0,0 +1,111 @@ +#pragma once + +#include "Resource/SHHandle.h" +#include "Math/Vector/SHVec4.h" +#include "ECS_Base/Components/SHComponent.h" +#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" + +namespace SHADE +{ + class SHVkBuffer; + class SHVkDescriptorSetGroup; + class SHVkDescriptorSetLayout; + + class SHParticleEmitterComponent : public SHComponent + { + private: + struct GPUEmitterStruct + { + //! Minimum emitting angular range + SHVec4 angularMin; + + //! Maximum emitting angular range + SHVec4 angularMax; + + //! Spawn lifetime and size range (min and max) + SHVec4 lifeAndSizeRange; + }; + + struct GPUParticleStruct + { + //! Position of the particle + SHVec4 position; + + //! Rotation of the particle + SHVec4 rotation; + + //! Velocity of the particle + SHVec4 velocity; + + //! Acceleration of the particle + SHVec4 acceleration; + + //! x scale, x scale decay, y scale and y scale decay + SHVec4 scaleAndDecay; + + //! Life of the particle + float life; + + //! Texture into the desc array that the particle is using + uint32_t textureIndex; + }; + + //! Max number of particles of this emitter + uint32_t maxParticles; + + //! num bytes of all particles in 1 chunk (1 frame) + uint32_t chunkSize; + + //! emission count per emit + uint32_t emissionCount; + + //! emission interval of the emitter + float emissionInterval; + + //! Counter that decreases to 0 from emissionInterval. When 0, emit particles. + float timeBeforeEmission; + + //! Data for the emitter + Handle emitterData; + + //! GPU Particle data + Handle particleData; + + //! Freelist data + Handle freelistData; + + //! Indices data + Handle indicesData; + + //! draw call data + Handle drawCallData; + + //! We need more descriptor sets because the operations on a frame's particle data needs to rely on the previous frame's. Each set + //! will contain 2 bindings that point to 2 buffers (input and output). + Handle particleDescriptorSet; + + //! Emitter's data on the CPU side. To be copied to GPU. + GPUEmitterStruct cpuEmitterData; + + //! If passive, emitter emits particles based on timer above. + bool isPassive; + + //! Have the particle system initialize variables in this component when this is false + bool initialized; + + //! If true, particle system will emit particles in Run function. Sets to false every frame. + bool toEmit; + + //! For all the dynamic SSBOs in the descriptor set + std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS> dynamicOffsets{}; + + public: + void OnCreate(void) override final; + void OnDestroy(void) override final; + + void Emit (void) noexcept; + + friend class SHParticleSubSystem; + + }; +} diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSustem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSustem.h deleted file mode 100644 index da806480..00000000 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSustem.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include "Resource/SHHandle.h" -#include "Graphics/Pipeline/SHPipelineState.h" -#include "Math/SHMatrix.h" - -namespace SHADE -{ - class SHVkLogicalDevice; - class SHVkDescriptorPool; - class SHVkDescriptorSetGroup; - class SHVkDescriptorSetLayout; - class SHVkBuffer; - class SHLightComponent; - class SHVkCommandBuffer; - class SHVkPipeline; - class SHVkPipelineLayout; - class SHVkRenderpass; - class SHSubpass; - class SHVkShaderModule; - class SHRenderer; - - - - class SHParticleSubSystem - { - private: - - Handle logicalDevice; - - - public: - void Init(Handle device, Handle compatibleRenderpass, Handle subpass) noexcept; - - void Run(uint32_t frameIndex) noexcept; - - void Render(Handle cmdBuffer, Handle renderer, uint32_t frameIndex) noexcept; - void Exit(void) noexcept; - - }; -} diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp index eb3c4f1a..7c3d9c74 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp @@ -1,7 +1,309 @@ #include "SHpch.h" -#include "SHParticleSubSustem.h" +#include "SHParticleSubSystem.h" +#include "Graphics/Pipeline/SHPipelineLayoutParams.h" +#include "Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" +#include "Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h" +#include "ECS_Base/Managers/SHComponentManager.h" +#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" +#include "Graphics/Descriptors/SHVkDescriptorSetLayout.h" +#include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h" +#include "Math/Transform/SHTransformComponent.h" +#include "Graphics/Buffers/SHVkBuffer.h" namespace SHADE { - + + void SHParticleSubSystem::InitializeComponent(SHParticleEmitterComponent& comp) noexcept + { + uint32_t emitterStructAligned = logicalDevice->PadSSBOSize(sizeof (SHParticleEmitterComponent::GPUEmitterStruct)); + uint32_t particleStructAligned = logicalDevice->PadUBOSize(sizeof (SHParticleEmitterComponent::GPUParticleStruct)); + uint32_t sizeofIndirectCmd = static_cast(sizeof(vk::DrawIndirectCommand)); + uint32_t sizeofUint = static_cast(sizeof(uint32_t)); + + // TODO: temporary only. + static constexpr uint32_t NUM_PARTICLES = 500; + comp.maxParticles = NUM_PARTICLES; + + // offset into the buffer for input and output + uint32_t const PARTICLE_FRAME_CHUNK_SIZE = (particleStructAligned * comp.maxParticles); + + // Buffer Initialization + { + // count, value + std::vector freelistInit(comp.maxParticles + 1, 0); + freelistInit[0] = comp.maxParticles; + + // Particle emitter buffer. Multiple copies, Host-visible mapped. We want multiple copies because we'll be writing to it from the CPU. We don't want to do that while the GPU + // is using it during compute operations so we write to another portion. + comp.emitterData = logicalDevice->CreateBuffer(SHGraphicsConstants::NUM_FRAME_BUFFERS * emitterStructAligned, nullptr, 0, vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT); + + // buffer for particle data: pure GPU memory, no transfers, no flags. We want to triple buffer this so that we can submit work to the GPU + // without having to wait for rendering to finish reading the data + comp.particleData = logicalDevice->CreateBuffer(SHGraphicsConstants::NUM_FRAME_BUFFERS * particleStructAligned * NUM_PARTICLES, nullptr, 0, vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, {}); + + // Buffer for freelist data. 1 copy only, host-visible mapped. We only need 1 copy because it is only required in compute. If it was used or read in another + // stage we would need more copies. + comp.freelistData = logicalDevice->CreateBuffer(sizeofUint * (comp.maxParticles + 1), freelistInit.data(), sizeofUint * (comp.maxParticles + 1), vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT); + + // Buffer for indices. NUM_FRAME_BUFFERS copies since it's used in rendering. host-visible mapped. + comp.indicesData = logicalDevice->CreateBuffer(sizeofUint * comp.maxParticles, nullptr, 0, vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT); + + // Draw call data will not be tampered with after this initialization except for one variable: instanceCount, which will be modified from compute shader + std::array indirectCommands{}; + for (auto& cmd : indirectCommands) + { + cmd.vertexCount = 4; + cmd.firstVertex = 0; + cmd.firstInstance = 0; + cmd.instanceCount = 0; + } + + // 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); + + } + + // Descriptor set initialization + { + // Get particle desc set layout + auto descSetLayout = SHGraphicsPredefinedData::GetPredefinedDescSetLayouts(SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes::PARTICLES); + + // Since we are populating the set as is, the set index will be 0 + static constexpr uint32_t PARTICLE_DATA_SET_INDEX = 0; + + // Variable desc counts, all ignored anyway (This is required but its a dumb interface. You can only blame yourself, Brandon. ) + std::vector const VARIABLE_COUNTS = {0u,0u,0u,0u,0u}; + + // allocate new desc set + comp.particleDescriptorSet = descPool->Allocate(descSetLayout, VARIABLE_COUNTS); + + // convenience handle + auto set = comp.particleDescriptorSet; + + // After buffers are created, we want to populate all bindings(6) with the buffers + set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_EMITTER_DATA, { &comp.emitterData, 1 }, 0, emitterStructAligned); + set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INPUT_DATA, { &comp.particleData, 1 }, 0, PARTICLE_FRAME_CHUNK_SIZE); // input and output will be th same until we bind using dynamic offsets + set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_OUTPUT_DATA, { &comp.particleData, 1 }, 0, PARTICLE_FRAME_CHUNK_SIZE); + set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_FREELIST_DATA, { &comp.freelistData, 1 }, 0, sizeofUint * (comp.maxParticles + 1)); + set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INDICES_DATA, { &comp.indicesData, 1 }, 0, sizeofUint * (comp.maxParticles)); + set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_DRAW_DATA, { &comp.drawCallData, 1 }, 0, sizeofIndirectCmd); + } + + comp.initialized = true; + comp.timeBeforeEmission = comp.emissionInterval; + comp.toEmit = false; + comp.chunkSize = PARTICLE_FRAME_CHUNK_SIZE; + + for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i) + { + auto& offsets = comp.dynamicOffsets[i]; + + uint32_t inputOffset = PARTICLE_FRAME_CHUNK_SIZE * ((i + SHGraphicsConstants::NUM_FRAME_BUFFERS - 1) % SHGraphicsConstants::NUM_FRAME_BUFFERS); // take previous frame's data + uint32_t outputOffset = PARTICLE_FRAME_CHUNK_SIZE * i; + + // In the order of: + // 1. Emitter data + // 2. Particle input + // 3. Particle output + // 4. Particle draw data + offsets[DYOFF_INDEX_EMITTER] = i * emitterStructAligned; + offsets[DYOFF_INDEX_PARTICLE_INPUT] = inputOffset; + offsets[DYOFF_INDEX_PARTICLE_OUTPUT] = outputOffset; + offsets[DYOFF_INDEX_INDICES_DATA] = i * sizeofUint * comp.maxParticles; + offsets[DYOFF_INDEX_DRAW_DATA] = i * sizeofIndirectCmd; + } + } + + void SHParticleSubSystem::EmitComponent(Handle cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept + { + auto const& mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING); + auto* transform = SHComponentManager::GetComponent(comp.GetEID()); + + // bind the descriptor sets required for emitting particles + cmdBuffer->BindDescriptorSet(comp.particleDescriptorSet, SH_PIPELINE_TYPE::COMPUTE, mappings.at(SHPredefinedDescriptorTypes::PARTICLES), comp.dynamicOffsets[frameIndex]); + + cmdBuffer->SetPushConstantVariable("EmitterPushConstant.emitterPosition", transform->GetWorldPosition(), SH_PIPELINE_TYPE::COMPUTE); + cmdBuffer->SetPushConstantVariable("EmitterPushConstant.emissionCount", comp.emissionCount, SH_PIPELINE_TYPE::COMPUTE); + + // emit particles + cmdBuffer->ComputeDispatch((comp.emissionCount / EMITTER_WORKGROUP_SIZE) + 1, 1, 1); + } + + void SHParticleSubSystem::UpdateCompoennt(Handle cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept + { + 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]); + + // dispatch the compute shaders to update particles + cmdBuffer->ComputeDispatch((comp.maxParticles / EMITTER_WORKGROUP_SIZE) + 1, 1, 1); + } + + void SHParticleSubSystem::RenderComponent(Handle cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept + { + + } + + void SHParticleSubSystem::Init(Handle device, Handle inDescPool, Handle compatibleRenderpass, Handle subpass, Handle VS, Handle FS, Handle emitCS, Handle defaultUpdateCS) noexcept + { + descPool = inDescPool; + logicalDevice = device; + + /*-----------------------------------------------------------------------*/ + /* INITIALIZE ALL PIPELINES */ + /*-----------------------------------------------------------------------*/ + SHPipelineLayoutParams plParams + { + .shaderModules = {VS, FS}, + .predefinedDescSetLayouts = SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING).descSetLayouts + }; + + renderingPipelineData.pipelineLayout = logicalDevice->CreatePipelineLayout(plParams); + renderingPipelineData.pipeline = logicalDevice->CreateGraphicsPipeline(renderingPipelineData.pipelineLayout, nullptr, compatibleRenderpass, subpass); + + SHPipelineLayoutParams emitPlParams + { + .shaderModules = {emitCS}, + .predefinedDescSetLayouts = SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING).descSetLayouts + }; + + emittingPipelineData.pipelineLayout = logicalDevice->CreatePipelineLayout(emitPlParams); + emittingPipelineData.pipeline = logicalDevice->CreateComputePipeline(emittingPipelineData.pipelineLayout); + + SHPipelineLayoutParams defaultUpdatePlParams + { + .shaderModules = {defaultUpdateCS}, + .predefinedDescSetLayouts = SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING).descSetLayouts + }; + + defaultUpdatePipelineData.pipelineLayout = logicalDevice->CreatePipelineLayout(defaultUpdatePlParams); + defaultUpdatePipelineData.pipeline = logicalDevice->CreateComputePipeline(defaultUpdatePipelineData.pipelineLayout); + + + /*-----------------------------------------------------------------------*/ + /* OTHER INITIALIZATION */ + /*-----------------------------------------------------------------------*/ + SHComponentManager::CreateComponentSparseSet(); + } + + void SHParticleSubSystem::Run(Handle cmdBuffer, uint32_t frameIndex, float dt) noexcept + { + auto& emitters = SHComponentManager::GetDense(); + auto const& mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING); + + // Get offset into GPU emitter data (for updating) + uint32_t emitterDataOffset = frameIndex * sizeof (SHParticleEmitterComponent::GPUEmitterStruct); + + // Barriers to make sure emitting shader is done completely before update is run. + // Every emitter will have its own barrier. + std::vector preUpdateBarriers{}; + preUpdateBarriers.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. + + /*-----------------------------------------------------------------------*/ + /* BEGIN EMITTING PARTICES */ + /*-----------------------------------------------------------------------*/ + + // TODO: Might need to issue a barrier here for input particle data + + // bind the pipeline for emitting particles + cmdBuffer->BindPipeline(emittingPipelineData.pipeline); + + // Generic data + SHGlobalDescriptorSets::BindGenericAndTextureData(logicalDevice, cmdBuffer, SH_PIPELINE_TYPE::COMPUTE, mappings.at(SHPredefinedDescriptorTypes::STATIC_DATA), frameIndex); + + uint32_t i = 0; + for (auto& emitter : emitters) + { + if (!emitter.initialized) + InitializeComponent(emitter); + + // Set emitter emit flag to true here if there are ready to be emitted + if (emitter.isPassive) + { + // decrement emission timer + emitter.timeBeforeEmission -= dt; + + // Check if time to emit + if (emitter.timeBeforeEmission <= 0.0f) + { + // reset timer + emitter.timeBeforeEmission = emitter.emissionInterval; + + // Emit later + emitter.toEmit = true; + } + } + + if (emitter.toEmit) // take note that if emitter is not passive, this can also be set to true outside of this function + { + // Copy data to host visible buffer of emitter + emitter.emitterData->WriteToMemory (&emitter.cpuEmitterData, sizeof (SHParticleEmitterComponent::GPUEmitterStruct), 0, emitterDataOffset); + + // Call emit function here + 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; + + emitter.toEmit = false; + ++i; + } + + // issue the barrier to wait + cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {}, preUpdateBarriers, {}); + + /*-----------------------------------------------------------------------*/ + /* EMITTING PARTICLES DONE, BEGIN UPDATES.... */ + /*-----------------------------------------------------------------------*/ + + // bind the pipeline for updating + cmdBuffer->BindPipeline(defaultUpdatePipelineData.pipeline); + + for (auto& emitter : emitters) + { + UpdateCompoennt(cmdBuffer, emitter, frameIndex); + } + + + } + + void SHParticleSubSystem::Render(Handle cmdBuffer, Handle renderer, uint32_t frameIndex) noexcept + { + auto& emitters = SHComponentManager::GetDense(); + + // TODO: Issue barrier for output particle data. Semaphore should also be issued outside in SHGraphicsSystem + for (auto& emitter : emitters) + { + + } + } + + void SHParticleSubSystem::Exit(void) noexcept + { + + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h new file mode 100644 index 00000000..ed697a59 --- /dev/null +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h @@ -0,0 +1,93 @@ +#pragma once + +#include "Resource/SHHandle.h" +#include "Graphics/Pipeline/SHPipelineState.h" +#include "Math/SHMatrix.h" + +namespace SHADE +{ + class SHVkLogicalDevice; + class SHVkDescriptorPool; + class SHVkDescriptorSetGroup; + class SHVkDescriptorSetLayout; + class SHVkBuffer; + class SHLightComponent; + class SHVkCommandBuffer; + class SHVkPipeline; + class SHVkPipelineLayout; + class SHVkRenderpass; + class SHSubpass; + class SHVkShaderModule; + class SHRenderer; + class SHParticleEmitterComponent; + + + + class SHParticleSubSystem + { + private: + static constexpr uint32_t EMITTER_WORKGROUP_SIZE = 128; + static constexpr uint32_t DYOFF_INDEX_EMITTER = 0; + static constexpr uint32_t DYOFF_INDEX_PARTICLE_INPUT = 1; + static constexpr uint32_t DYOFF_INDEX_PARTICLE_OUTPUT = 2; + static constexpr uint32_t DYOFF_INDEX_INDICES_DATA = 3; + static constexpr uint32_t DYOFF_INDEX_DRAW_DATA = 4; + + + // To hold data for a pipeline and pipeline layout. + // We want this here because particles require 3 pipeline sets: + // - Rendering + // - Emit Compute + // - Update Compute + struct PipelineData + { + //! Pipeline + Handle pipeline; + + //! Pipeline layout for pipeline creation + Handle pipelineLayout; + }; + +#if 0 // not used, mainly for convenience to show what shaders use + // Push constant data for emitters + struct EmitterShaderPC + { + //! Emitter position + SHVec4 emitterPosition; + + //! emission count for 1 single emission + uint32_t emissionCount; + }; +#endif + + //! Logical device for creation and destruction + Handle logicalDevice; + + //! Pipeline data for rendering particles + PipelineData renderingPipelineData; + + //! Pipeline data for emitting particles + PipelineData emittingPipelineData; + + //! Pipeline data for updating particles + PipelineData defaultUpdatePipelineData; + + //! Desc pool for particle component desc set allocation + Handle descPool; + + + void InitializeComponent (SHParticleEmitterComponent& comp) noexcept; + void EmitComponent (Handle cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept; + void UpdateCompoennt(Handle cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept; + void RenderComponent(Handle cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept; + + public: + void Init(Handle device, Handle inDescPool, Handle compatibleRenderpass, Handle subpass, Handle VS, Handle FS, Handle emitCS, Handle defaultUpdateCS) noexcept; + + void Run(Handle cmdBuffer, uint32_t frameIndex, float dt) noexcept; + + void Render(Handle cmdBuffer, Handle renderer, uint32_t frameIndex) noexcept; + void Exit(void) noexcept; + + }; +} diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.cpp index a7a3d2ed..3edf0983 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.cpp @@ -61,7 +61,7 @@ namespace SHADE MakeDirty(); } - void SHTextRenderableComponent::SetColour(SHColour const& newColor) noexcept + void SHTextRenderableComponent::SetColor(SHColour const& newColor) noexcept { color = newColor; } @@ -87,7 +87,7 @@ namespace SHADE return fontHandle; } - SHADE::SHColour const& SHTextRenderableComponent::GetColour(void) const noexcept + SHADE::SHColour const& SHTextRenderableComponent::GetColor(void) const noexcept { return color; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h index d34e7c38..9d31cdd8 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h @@ -52,11 +52,11 @@ namespace SHADE /*-----------------------------------------------------------------------*/ void SetText (std::string_view newText) noexcept; void SetFont(Handle font) noexcept; - void SetColour(SHColour const& newColor) noexcept; + void SetColor(SHColour const& newColor) noexcept; std::string const& GetText (void) const noexcept; Handle GetFont (void) const noexcept; - SHColour const& GetColour (void) const noexcept; + SHColour const& GetColor (void) const noexcept; friend class SHTextRenderingSubSystem; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.cpp index 77dd66c8..91c11e60 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.cpp @@ -42,16 +42,26 @@ namespace SHADE return mesh; } - SHVec4 const& SHTrajectoryRenderableComponent::GetStartColor(void) const noexcept + SHVec3 const& SHTrajectoryRenderableComponent::GetStartColor(void) const noexcept { return startColor; } - SHVec4 const& SHTrajectoryRenderableComponent::GetEndColor(void) const noexcept + SHVec3 const& SHTrajectoryRenderableComponent::GetEndColor(void) const noexcept { return endColor; } + float SHTrajectoryRenderableComponent::GetStartAlpha(void) const noexcept + { + return startAlpha; + } + + float SHTrajectoryRenderableComponent::GetEndAlpha(void) const noexcept + { + return endAlpha; + } + float SHTrajectoryRenderableComponent::GetColorEvolveRate(void) const noexcept { return colorEvolveRate; @@ -67,17 +77,27 @@ namespace SHADE positions = inPositions; } - void SHTrajectoryRenderableComponent::SetStartColor(SHVec4 color) noexcept + void SHTrajectoryRenderableComponent::SetStartColor(SHVec3 color) noexcept { startColor = color; } - void SHTrajectoryRenderableComponent::SetEndColor(SHVec4 color) noexcept + void SHTrajectoryRenderableComponent::SetEndColor(SHVec3 color) noexcept { endColor = color; } + void SHTrajectoryRenderableComponent::SetStartAlpha(float a) noexcept + { + startAlpha = a; + } + + void SHTrajectoryRenderableComponent::SetEndAlpha(float a) noexcept + { + endAlpha = a; + } + void SHTrajectoryRenderableComponent::SetColorEvolveRate(float rate) noexcept { colorEvolveRate = rate; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h b/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h index d6f7be12..f3744d83 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h @@ -10,7 +10,7 @@ namespace SHADE { class SHMesh; - class SHTrajectoryRenderableComponent : public SHComponent + class SH_API SHTrajectoryRenderableComponent : public SHComponent { private: @@ -21,10 +21,16 @@ namespace SHADE std::vector positions; //! Starting color of the trajectory - SHVec4 startColor; + SHVec3 startColor; //! Color the trajectory should evolve to the longer it is - SHVec4 endColor; + SHVec3 endColor; + + //! Starting alpha of the trajectory + float startAlpha; + + //! end alpha of the trajectory + float endAlpha; //! evolving rate of the color float colorEvolveRate; @@ -35,14 +41,18 @@ namespace SHADE /*-----------------------------------------------------------------------*/ void SetMesh(Handle newMesh) noexcept; void SetPositions (std::vector const& inPositions) noexcept; - void SetStartColor(SHVec4 startColor) noexcept; - void SetEndColor (SHVec4 endColor) noexcept; - void SetColorEvolveRate (float rate) noexcept; + void SetStartColor(SHVec3 startColor) noexcept; + void SetEndColor (SHVec3 endColor) noexcept; + void SetStartAlpha(float a) noexcept; + void SetEndAlpha (float a) noexcept; + void SetColorEvolveRate(float rate) noexcept; std::vector GetPositions (void) const noexcept; Handle GetMesh (void) const noexcept; - SHVec4 const& GetStartColor (void) const noexcept; - SHVec4 const& GetEndColor (void) const noexcept; + SHVec3 const& GetStartColor (void) const noexcept; + SHVec3 const& GetEndColor (void) const noexcept; + float GetStartAlpha (void) const noexcept; + float GetEndAlpha (void) const noexcept; float GetColorEvolveRate (void) const noexcept; void OnCreate(void) override final; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderingSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderingSubSystem.cpp index 802d085d..61631925 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderingSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderingSubSystem.cpp @@ -59,8 +59,8 @@ namespace SHADE .srcColorBlendFactor = vk::BlendFactor::eSrcAlpha, .dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha, .colorBlendOp = vk::BlendOp::eAdd, - .srcAlphaBlendFactor = vk::BlendFactor::eOne, - .dstAlphaBlendFactor = vk::BlendFactor::eZero, + .srcAlphaBlendFactor = vk::BlendFactor::eSrcAlpha, + .dstAlphaBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha, .alphaBlendOp = vk::BlendOp::eAdd, .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA, } @@ -84,12 +84,18 @@ namespace SHADE // If has positions, feed data to buffer. if (comp.HasPositions()) { + auto meshHandle = comp.GetMesh(); + + // dont do anything if no mesh + if (!meshHandle) + continue; + SHTransformComponent* transform = SHComponentManager::GetComponent_s(comp.GetEID()); if (transform) { // convenient variable - SHVec4 const& startColor = comp.GetStartColor(); - SHVec4 const& endColor = comp.GetEndColor(); + SHVec3 const& startColor = comp.GetStartColor(); + SHVec3 const& endColor = comp.GetEndColor(); float colorEvolveRate = comp.GetColorEvolveRate(); // trs to be reused @@ -104,7 +110,6 @@ namespace SHADE // Will be used for baseInstance later uint32_t oldTransformDataSize = transformData.size(); - auto meshHandle = comp.GetMesh(); auto const& positions = comp.GetPositions(); for (auto& pos : positions) @@ -118,7 +123,8 @@ namespace SHADE colorData.push_back(currentColor); // evolve color - currentColor = SHVec4::Lerp(startColor, endColor, lerpValue); + currentColor = SHVec3::Lerp(startColor, endColor, lerpValue); + currentColor.w = SHMath::Lerp (comp.GetStartAlpha(), comp.GetEndAlpha(), lerpValue); // evolve lerp value and clamp to 1 lerpValue = std::max (1.0f, lerpValue + colorEvolveRate); diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index 9fceb10d..2c212e5f 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -15,6 +15,7 @@ #include "Graphics/MiddleEnd/TextRendering/SHFont.h" #include "Animation/SHAnimatorComponent.h" #include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" +#include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h" namespace YAML { @@ -353,12 +354,14 @@ namespace YAML { static constexpr std::string_view TEXT_YAML_TAG = "Text"; static constexpr std::string_view FONT_YAML_TAG = "Font"; + static constexpr std::string_view COLOR_YAML_TAG = "Color"; static YAML::Node encode(SHTextRenderableComponent const& rhs) { YAML::Node node; node[TEXT_YAML_TAG.data()] = rhs.GetText(); auto font = rhs.GetFont(); + SHColour const& textColor = rhs.GetColor(); if (font) { node[FONT_YAML_TAG.data()] = SHResourceManager::GetAssetID(rhs.GetFont()).value_or(0); @@ -367,6 +370,7 @@ namespace YAML { node[FONT_YAML_TAG.data()] = 0; } + node[COLOR_YAML_TAG.data()] = SHVec4 (textColor); return node; } static bool decode(YAML::Node const& node, SHTextRenderableComponent& rhs) @@ -385,11 +389,15 @@ namespace YAML rhs.SetFont(SHResourceManager::LoadOrGet(node[FONT_YAML_TAG.data()].as())); } + if (node[COLOR_YAML_TAG.data()].IsDefined()) + { + rhs.SetColor(node[COLOR_YAML_TAG.data()].as()); + } return true; } }; - + template<> struct convert { @@ -417,4 +425,37 @@ namespace YAML } }; + template<> + struct convert + { + static constexpr std::string_view MESH_YAML_TAG = "Mesh"; + static constexpr std::string_view START_COLOR_YAML_TAG = "Start Color"; + static constexpr std::string_view END_COLOR_YAML_TAG = "End Color"; + static constexpr std::string_view COLOR_EVAL_RATE_YAML_TAG = "Color Eval Rate "; + + static YAML::Node encode(SHTrajectoryRenderableComponent const& rhs) + { + YAML::Node node; + node[MESH_YAML_TAG.data()] = SHResourceManager::GetAssetID(rhs.GetMesh()).value_or(0); + node[START_COLOR_YAML_TAG.data()] = SHVec3(rhs.GetStartColor()); + node[END_COLOR_YAML_TAG.data()] = SHVec3(rhs.GetEndColor()); + node[COLOR_EVAL_RATE_YAML_TAG.data()] = rhs.GetColorEvolveRate(); + + return node; + } + static bool decode(YAML::Node const& node, SHTrajectoryRenderableComponent& rhs) + { + if (node[MESH_YAML_TAG.data()].IsDefined()) + rhs.SetMesh(SHResourceManager::LoadOrGet(node[MESH_YAML_TAG.data()].as())); + if (node[START_COLOR_YAML_TAG.data()].IsDefined()) + rhs.SetStartColor(node[START_COLOR_YAML_TAG.data()].as()); + if (node[END_COLOR_YAML_TAG.data()].IsDefined()) + rhs.SetEndColor(node[END_COLOR_YAML_TAG.data()].as()); + if (node[COLOR_EVAL_RATE_YAML_TAG.data()].IsDefined()) + rhs.SetColorEvolveRate(node[COLOR_EVAL_RATE_YAML_TAG.data()].as()); + + return true; + } + }; + } diff --git a/SHADE_Managed/src/Components/TrajectoryRenderable.cxx b/SHADE_Managed/src/Components/TrajectoryRenderable.cxx new file mode 100644 index 00000000..4b762338 --- /dev/null +++ b/SHADE_Managed/src/Components/TrajectoryRenderable.cxx @@ -0,0 +1,83 @@ +#include "SHpch.h" + +#include "TrajectoryRenderable.hxx" +#include "Assets/NativeAsset.hxx" +#include "Utility/Convert.hxx" + + +namespace SHADE +{ + TrajectoryRenderable::TrajectoryRenderable(Entity entity) + :Component(entity) + { + + } + + MeshAsset TrajectoryRenderable::Mesh::get() + { + auto mesh = GetNativeComponent()->GetMesh(); + return mesh ? MeshAsset(mesh) : MeshAsset(); + } + void TrajectoryRenderable::Mesh::set(MeshAsset value) + { + if (value) + { + GetNativeComponent()->SetMesh(Handle()); + } + else + { + GetNativeComponent()->SetMesh(value.NativeObject); + } + } + + + void TrajectoryRenderable::StartColor::set(Vector3 val) + { + GetNativeComponent()->SetStartColor(Convert::ToNative(val)); + } + + Vector3 TrajectoryRenderable::StartColor::get() + { + return Convert::ToCLI(GetNativeComponent()->GetStartColor()); + } + + void TrajectoryRenderable::EndColor::set(Vector3 val) + { + GetNativeComponent()->SetEndColor(Convert::ToNative(val)); + } + + Vector3 TrajectoryRenderable::EndColor::get() + { + return Convert::ToCLI(GetNativeComponent()->GetEndColor()); + } + + void TrajectoryRenderable::StartAlpha::set(float val) + { + GetNativeComponent()->SetStartAlpha(val); + } + + float TrajectoryRenderable::StartAlpha::get() + { + return GetNativeComponent()->GetStartAlpha(); + } + + void TrajectoryRenderable::EndAlpha::set(float val) + { + GetNativeComponent()->SetEndAlpha(val); + } + + float TrajectoryRenderable::EndAlpha::get() + { + return GetNativeComponent()->GetEndAlpha(); + } + + void TrajectoryRenderable::ColorEvolveRate::set(float val) + { + GetNativeComponent()->SetColorEvolveRate(val); + } + + float TrajectoryRenderable::ColorEvolveRate::get() + { + return GetNativeComponent()->GetColorEvolveRate(); + } +} \ No newline at end of file diff --git a/SHADE_Managed/src/Components/TrajectoryRenderable.hxx b/SHADE_Managed/src/Components/TrajectoryRenderable.hxx new file mode 100644 index 00000000..37a350ad --- /dev/null +++ b/SHADE_Managed/src/Components/TrajectoryRenderable.hxx @@ -0,0 +1,87 @@ +/************************************************************************************//*! +\file TrajectoryRenderable.hxx +\author Brandon Mak, brandon.hao, +\par email: brandon.hao\@digipen.edu +\date 1st March, 2023 +\brief Contains the definition of the managed Renderable class with the + declaration of functions for working with it. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// Project Includes +#include "Components/Component.hxx" +#include "Math/Quaternion.hxx" +// External Dependencies +#include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h" +#include "Graphics/Color.hxx" +#include "Assets/MeshAsset.hxx" + +namespace SHADE +{ + /// + /// CLR version of the SHADE Engine's SHRenderableComponent. + /// + public ref class TrajectoryRenderable : public Component + { + internal: + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + /// + /// Constructs a Trajectory Renderable Component that represents a native Trajectory Renderable + /// component tied to the specified Entity. + /// + /// Entity that this Component will be tied to. + TrajectoryRenderable(Entity entity); + + public: + /*-----------------------------------------------------------------------------*/ + /* Properties */ + /*-----------------------------------------------------------------------------*/ + /// + /// Mesh used to render this Renderable. + /// + property MeshAsset Mesh + { + MeshAsset get(); + void set(MeshAsset value); + } + + property Vector3 StartColor + { + Vector3 get(); + void set (Vector3 val); + } + + property Vector3 EndColor + { + Vector3 get(); + void set(Vector3 val); + } + + property float StartAlpha + { + float get(); + void set (float val); + } + + property float EndAlpha + { + float get(); + void set(float val); + } + + property float ColorEvolveRate + { + float get(); + void set(float val); + } + }; +} + diff --git a/SHADE_Managed/src/Engine/ECS.cxx b/SHADE_Managed/src/Engine/ECS.cxx index 38596010..5b73b64e 100644 --- a/SHADE_Managed/src/Engine/ECS.cxx +++ b/SHADE_Managed/src/Engine/ECS.cxx @@ -46,6 +46,8 @@ of DigiPen Institute of Technology is prohibited. #include "Components\UIElement.hxx" #include "Components\Canvas.hxx" #include "Components\Slider.hxx" +#include "Components\TrajectoryRenderable.hxx" +#include "Graphics\MiddleEnd\TrajectoryRendering\SHTrajectoryRenderableComponent.h" @@ -335,6 +337,7 @@ namespace SHADE componentMap.Add(createComponentSet()); componentMap.Add(createComponentSet()); componentMap.Add(createComponentSet()); + componentMap.Add(createComponentSet()); } /*---------------------------------------------------------------------------------*/