Merge pull request #430 from SHADE-DP/SP3-1-Rendering

Improved particles and trajectory rendering
This commit is contained in:
XiaoQiDigipen 2023-03-20 16:55:28 +08:00 committed by GitHub
commit 600013bb82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 1410 additions and 152 deletions

View File

@ -22,18 +22,18 @@
Scripts: ~ Scripts: ~
- EID: 1 - EID: 1
Name: Raccoon Name: Raccoon
IsActive: true IsActive: false
NumberOfChildren: 1 NumberOfChildren: 1
Components: Components:
Transform Component: Transform Component:
Translate: {x: 0, y: 0.201105013, z: 0} Translate: {x: 0, y: 0.201105013, z: 0}
Rotate: {x: 0.00523597933, y: -2.96353412, z: -6.40293041e-10} Rotate: {x: 0.00523597933, y: -2.96353412, z: -6.40293041e-10}
Scale: {x: 1.00000191, y: 1, z: 1.00000191} Scale: {x: 1.00000191, y: 1, z: 1.00000191}
IsActive: true IsActive: false
Renderable Component: Renderable Component:
Mesh: 149697411 Mesh: 149697411
Material: 126974645 Material: 126974645
IsActive: true IsActive: false
Scripts: ~ Scripts: ~
- EID: 3 - EID: 3
Name: Bag Name: Bag
@ -87,18 +87,18 @@
Scripts: ~ Scripts: ~
- EID: 5 - EID: 5
Name: Floor Name: Floor
IsActive: true IsActive: false
NumberOfChildren: 0 NumberOfChildren: 0
Components: Components:
Transform Component: Transform Component:
Translate: {x: 0, y: 0.0810000002, z: 0} Translate: {x: 0, y: 0.0810000002, z: 0}
Rotate: {x: -1.57079625, y: 0, z: -0} Rotate: {x: -1.57079625, y: 0, z: -0}
Scale: {x: 50, y: 49.9999924, z: 49.9999924} Scale: {x: 50, y: 49.9999924, z: 49.9999924}
IsActive: true IsActive: false
Renderable Component: Renderable Component:
Mesh: 141771688 Mesh: 141771688
Material: 124370424 Material: 124370424
IsActive: true IsActive: false
Scripts: ~ Scripts: ~
- EID: 6 - EID: 6
Name: TrajectoryTest Name: TrajectoryTest
@ -146,3 +146,31 @@
"Color Eval Rate ": 0.192000002 "Color Eval Rate ": 0.192000002
IsActive: true IsActive: true
Scripts: ~ Scripts: ~
- EID: 7
Name: ParticleTest
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 0, y: 0.823412895, z: -4.31447983}
Rotate: {x: -0, y: 0, z: -0}
Scale: {x: 1, y: 1, z: 1}
IsActive: true
classSHADE::SHParticleEmitterComponent:
Emission Count: 15
Is Passive: true
Emission Interval: 0.0939999968
Min Life: 2
Max Life: 3
Minimum Speed: 3
Maximum Speed: 6
Minimum Size: 0
Maximum Size: 0.5
Size Decay: 0.990999997
Angular Ranges And Offset: {x: 6.19999981, y: 1.10000002, z: 0, w: 0.100000001}
Rotation Speed: 0.0309999995
Rotation Decay: 0.0199999996
Texture Asset ID: 63456868
Custom Update Shader Asset ID: 0
IsActive: true
Scripts: ~

View File

@ -1,24 +1,32 @@
#version 450 #version 450
#define PI 3.14159265f
layout(local_size_x = 128) in; layout(local_size_x = 128) in;
struct EmitterParameters struct EmitterParameters
{ {
vec4 angularMin; vec4 angularRangesAndOffsets;
vec4 angularMax; float minSpeed;
float maxSpeed;
float rotationSpeed;
float rotationDecay;
vec4 lifeAndSizeRange; // min life, max life, min size, max size vec4 lifeAndSizeRange; // min life, max life, min size, max size
} float sizeDecay;
uint textureIndex;
float padding[2];
};
struct ParticleData struct ParticleData
{ {
vec4 position; vec4 position;
vec4 rotation; vec4 orientationSpeedDecay;
vec4 velocity; vec4 velocity;
vec4 acceleration; vec4 acceleration;
vec4 scaleAndDecay; vec4 scaleAndDecay;
float life; float life;
uint textureIndex; uint textureIndex;
} };
struct GenericData struct GenericData
{ {
@ -96,22 +104,86 @@ 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;
vec4 angularRangesAndOffsets = emitterParams.data.angularRangesAndOffsets;
float minSpeed = emitterParams.data.minSpeed;
float maxSpeed = emitterParams.data.maxSpeed;
if (emitterInvocationIndex >= emitterPushConstant.emissionCount) if (emitterInvocationIndex >= emitterPushConstant.emissionCount)
return; return;
// Freecount will start at max particles. Here we subtract every time we emit.
int freelistIndex = atomicAdd (freelist.freeCount, -1) - 1; int freelistIndex = atomicAdd (freelist.freeCount, -1) - 1;
if (freelistIndex < 0) if (freelistIndex < 0)
atomicAdd (freelist.freeCount, 1); atomicAdd (freelist.freeCount, 1);
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);
vec2 eulerAngles = vec2 (rand(seed) * angularRangesAndOffsets.x + angularRangesAndOffsets.z,
rand(seed) * angularRangesAndOffsets.y + angularRangesAndOffsets.w);
// Set its velocity
// particle.velocity.xyz = vec3 (cos(eulerAngles.x) * cos(eulerAngles.y),
// sin(eulerAngles.x) * cos(eulerAngles.y),
// sin(eulerAngles.y));
float bank = eulerAngles.y;
float cb = cos(bank);
float sb = sin(bank);
float ch = cos (eulerAngles.x);
float sh = sin (eulerAngles.x);
float cp = cos (0.0f);
float sp = sin (0.0f);
particle.velocity.xyz = mat3 (
(ch * cb + sh * sp * sb), (sb * cp), (-sh * cb + ch * sp * sb),
(-ch * sb + sh * sp * cb), (cb * cp), ( sb * sh + ch * sp * cb),
(sh * cp), (-sp), (ch * cp)
) * vec3 (1.0f, 0.0f, 0.0f);
particle.velocity *= map (rand (seed), 0.0f, 1.0f, minSpeed.x, maxSpeed.x);
// randomize life value that ranges from minLife to maxLife
particle.life = map (rand(seed), 0.0f, 1.0f, emitterParams.data.lifeAndSizeRange.x, emitterParams.data.lifeAndSizeRange.y);
float particleSize = map (rand(seed), 0.0f, 1.0f, emitterParams.data.lifeAndSizeRange.z, emitterParams.data.lifeAndSizeRange.w);
// Set size of particle
particle.scaleAndDecay.x = particleSize;
particle.scaleAndDecay.y = particleSize;
particle.scaleAndDecay.z = emitterParams.data.sizeDecay;
particle.scaleAndDecay.w = emitterParams.data.sizeDecay;
// Set the texture for the particle
particle.textureIndex = emitterParams.data.textureIndex;
// Set orientation and rotation speed
if (emitterParams.data.rotationSpeed != 0.0f)
particle.orientationSpeedDecay = vec4 (rand(seed) * PI, emitterParams.data.rotationSpeed, emitterParams.data.rotationDecay, 0.0f);
else
particle.orientationSpeedDecay = vec4 (0.0f);
particle.acceleration = vec4 (0.0f, -0.058f, 0.0f, 0.0f);
inputParticles.data[index] = particle;
} }

Binary file not shown.

View File

@ -0,0 +1,3 @@
Name: ParticleEmit_CS
ID: 49959611
Type: 2

View File

@ -0,0 +1,146 @@
#version 450
layout(local_size_x = 128) in;
struct DrawArraysIndirectArgs
{
uint count;
uint instanceCount;
uint first;
uint baseInstance;
};
struct ParticleData
{
vec4 position;
vec4 orientationSpeedDecay;
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 buffer 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];
// Get seed for randomization
uint pixel_index = uint (particle.position.x + particle.position.y + floatBitsToUint(genericDataBuffer.data.elapsedTime) * (gl_GlobalInvocationID.x + 1));
uint seed = pcg_hash (pixel_index);
if (particle.life > 0.0f)
{
// update position from velocity
particle.position += particle.velocity * genericDataBuffer.data.dt;
particle.velocity += vec4 (rand(seed) * particle.acceleration.x, rand(seed) * particle.acceleration.y, rand(seed) * particle.acceleration.z, 1.0f);
particle.life -= genericDataBuffer.data.dt;
if (particle.life < 0.0f || particle.scaleAndDecay.x < 0.0f || particle.scaleAndDecay.y < 0.0f)
{
particle.life = 0.0f;
particle.position.x = 9999.0f;
outputParticles.data[index] = particle;
freelist.freeIndices[atomicAdd(freelist.freeCount, 1)] = int (index);
return;
}
uint drawIndex = atomicAdd (indirectArgs.instanceCount, 1);
indices[drawIndex] = index;
}
outputParticles.data[index] = particle;
}

Binary file not shown.

View File

@ -0,0 +1,3 @@
Name: ParticleUpdateRandomAcc_CS
ID: 35838633
Type: 2

View File

@ -13,13 +13,13 @@ struct DrawArraysIndirectArgs
struct ParticleData struct ParticleData
{ {
vec4 position; vec4 position;
vec4 rotation; vec4 orientationSpeedDecay;
vec4 velocity; vec4 velocity;
vec4 acceleration; vec4 acceleration;
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,26 +116,37 @@ 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; // update position from velocity
particle.position += particle.velocity * genericDataBuffer.data.dt;
particle.velocity += particle.acceleration;
particle.life -= genericDataBuffer.data.dt;
particle.orientationSpeedDecay.x += particle.orientationSpeedDecay.y;
particle.scaleAndDecay.x *= particle.scaleAndDecay.z;
particle.scaleAndDecay.y *= particle.scaleAndDecay.w;
// particle.lifetime -= dt; if (particle.orientationSpeedDecay.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.orientationSpeedDecay.y -= particle.orientationSpeedDecay.z * genericDataBuffer.data.dt;
particle.position.x = 99999.0f; if (particle.orientationSpeedDecay.y < 0.0f)
particle.orientationSpeedDecay.y = 0.0f;
}
if (particle.life < 0.0f || particle.scaleAndDecay.x < 0.0f || particle.scaleAndDecay.y < 0.0f)
{
particle.life = 0.0f;
particle.position.x = 9999.0f;
outputParticles.data[index] = particle; outputParticles.data[index] = particle;
freelist.freeIndices[atomicAdd(freelist.freeCount, 1)] = int (index); freelist.freeIndices[atomicAdd(freelist.freeCount, 1)] = int (index);
return; return;
} }
outputParticles.data[index] = particle;
uint drawIndex = atomicAdd (indirectArgs.instanceCount, 1); uint drawIndex = atomicAdd (indirectArgs.instanceCount, 1);
indices[drawIndex] = index; indices[drawIndex] = index;
} }
outputParticles.data[index] = particle;
} }

Binary file not shown.

View File

@ -0,0 +1,3 @@
Name: ParticleUpdate_CS
ID: 36260925
Type: 2

View File

@ -0,0 +1,26 @@
#version 460 core
#extension GL_EXT_nonuniform_qualifier : require
layout (location = 0) out vec4 fragColor;
layout (set = 0, binding = 1) uniform sampler2D textures[]; // for textures (global)
// between shader stages
layout(location = 0) in struct
{
vec2 uv; // location = 0
} In;
// material stuff
layout(location = 1) flat in struct
{
uint textureIndex;
} InFlat;
void main ()
{
fragColor = vec4 (texture(textures [nonuniformEXT(InFlat.textureIndex)], In.uv));
if (fragColor.a < 0.01f)
discard;
}

Binary file not shown.

View File

@ -0,0 +1,3 @@
Name: Particle_FS
ID: 42509714
Type: 2

View File

@ -0,0 +1,101 @@
#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 orientationSpeedDecay;
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;
// material stuff
layout(location = 1) out struct
{
uint textureIndex; // location = 1
} OutFlat;
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 = particle.orientationSpeedDecay.x;
// float angle = atan (normalized.y, normalized.x);
vec2 particleScaleData = particle.scaleAndDecay.xy; // x and y
mat3 rotate = mat3 (1.0f);
rotate[0][0] = cos(angle);
rotate[0][1] = sin(angle);
rotate[1][0] = -sin(angle);
rotate[1][1] = cos(angle);
vec3 particlePos = rotate * vertexPos;
vec3 viewRight = normalize (vec3 (cameraData.viewMat[0][0], cameraData.viewMat[1][0], cameraData.viewMat[2][0]));
vec3 viewUp = normalize(vec3 (cameraData.viewMat[0][1], cameraData.viewMat[1][1], cameraData.viewMat[2][1]));
particlePos = particle.position.xyz + (viewRight * particlePos.x * particleScaleData.x) + (viewUp * particlePos.y * particleScaleData.y);
OutFlat.textureIndex = particle.textureIndex;
gl_Position = cameraData.vpMat * vec4(particlePos, 1.0f);
}

Binary file not shown.

View File

@ -0,0 +1,3 @@
Name: Particle_VS
ID: 35035037
Type: 2

View File

@ -8,7 +8,7 @@ const int ROTATION_KERNEL_W = 4;
const int ROTATION_KERNEL_H = 4; const int ROTATION_KERNEL_H = 4;
// can perhaps pass in as push constant. // can perhaps pass in as push constant.
const float RADIUS = 0.2f; const float RADIUS = 0.35f;
const float BIAS = 0.0025f; const float BIAS = 0.0025f;
layout(local_size_x = 16, local_size_y = 16) in; layout(local_size_x = 16, local_size_y = 16) in;

Binary file not shown.

View File

@ -15,3 +15,4 @@
#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h"
#include "AudioSystem/SHAudioListenerComponent.h" #include "AudioSystem/SHAudioListenerComponent.h"
#include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h" #include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h"
#include "Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h"

View File

@ -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,166 @@ namespace SHADE
ImGui::PopID(); ImGui::PopID();
} }
template<>
static void DrawComponent(SHParticleEmitterComponent* component)
{
if (!component)
return;
auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
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::DragInt("Emission Count", [comp = component]() {return comp->GetEmissionCount(); }, [comp = component](uint32_t count) {comp->SetEmissionCount(count);});
SHEditorWidgets::DragFloat("Emission Interval", [comp = component]() {return comp->GetEmissionInterval(); }, [comp = component](float interval) {comp->SetEmissionInterval(interval); });
SHEditorWidgets::DragFloat("Min Life", [comp = component]() {return comp->GetMinLife(); }, [comp = component](float val) {comp->SetMinLife(val); });
SHEditorWidgets::DragFloat("Max Life", [comp = component]() {return comp->GetMaxLife(); }, [comp = component](float val) {comp->SetMaxLife(val); });
SHEditorWidgets::DragFloat("Min Size", [comp = component]() {return comp->GetMinSize(); }, [comp = component](float val) {comp->SetMinSize(val); });
SHEditorWidgets::DragFloat("Max Size", [comp = component]() {return comp->GetMaxSize(); }, [comp = component](float val) {comp->SetMaxSize(val); });
SHEditorWidgets::DragFloat("Size Decay", [comp = component]() {return comp->GetSizeDecayMult(); }, [comp = component](float val) {comp->SetSizeDecayMult(val); }, {}, 0.0001f);
SHEditorWidgets::DragVec4("Angles and Offsets", {"yaw", "bank", "yaw off", "bank off"},
[comp = component]()
{
return comp->GetAngularRangesAndOffsets();
},
[comp = component](SHVec4 const& val)
{
comp->SetAngularRangesAndOffsets(val);
});
SHEditorWidgets::DragFloat("Min Speed",
[comp = component]()
{
return comp->GetMinSpeed();
},
[comp = component](float val)
{
comp->SetMinSpeed(val);
});
SHEditorWidgets::DragFloat("Max Speed",
[comp = component]()
{
return comp->GetMaxSpeed();
},
[comp = component](float val)
{
comp->SetMaxSpeed(val);
});
SHEditorWidgets::DragFloat("Rotation Speed",
[comp = component]()
{
return comp->GetRotationSpeed();
},
[comp = component](float val)
{
comp->SetRotationSpeed(val);
});
SHEditorWidgets::DragFloat("Rotation Decay",
[comp = component]()
{
return comp->GetRotationDecay();
},
[comp = component](float val)
{
comp->SetRotationDecay(val);
});
SHEditorWidgets::DragInt("Texture Index",
[comp = component]()
{
return comp->GetTextureAssetID();
},
[comp = component](AssetID val)
{
comp->SetTextureAssetID(val);
});
if (SHDragDrop::BeginTarget())
{
if (AssetID* payload = SHDragDrop::AcceptPayload<AssetID>(SHDragDrop::DRAG_RESOURCE))
{
Handle<SHTexture> texture = SHResourceManager::LoadOrGet<SHTexture>(*payload);
gfxSystem->BuildTextures();
if (texture)
{
component->SetTextureIndex(texture->TextureArrayIndex);
component->SetTextureAssetID(*payload);
}
else
{
SHLOG_WARNING("[] Attempted to load invalid texture! Texture for particle not set. ");
}
SHDragDrop::EndTarget();
}
}
SHEditorWidgets::InputText("Custom Update Shader",
[comp = component]()
{
auto customShader = comp->GetCustomUpdateShader();
if (customShader)
return customShader->GetName();
else
return std::string{};
},
[comp = component](std::string const& text)
{
}, {}, ImGuiSliderFlags_ReadOnly);
if (SHDragDrop::BeginTarget())
{
if (AssetID* payload = SHDragDrop::AcceptPayload<AssetID>(SHDragDrop::DRAG_RESOURCE))
{
Handle<SHVkShaderModule> shaderModule = SHResourceManager::LoadOrGet<SHVkShaderModule>(*payload);
if (shaderModule)
{
component->SetCustomUpdateShader(shaderModule);
component->SetCustomUpdateShaderAssetID(*payload);
}
else
{
SHLOG_WARNING("[] Attempted to load invalid shader! Custom update shader for particles not set. ");
}
SHDragDrop::EndTarget();
}
}
ImGui::SameLine();
if (ImGui::Button("Reset"))
{
component->SetCustomUpdateShader({});
component->SetCustomUpdateShaderAssetID(INVALID_ASSET_ID);
}
SHEditorWidgets::CheckBox("Is Passive", [comp = component]() {return comp->GetPassive(); }, [comp = component](bool flag) {comp->SetPassive(flag); });
}
else
{
DrawContextMenu(component);
}
ImGui::PopID();
}
} }

View File

@ -26,6 +26,7 @@
#include "SHEditorComponentView.h" #include "SHEditorComponentView.h"
#include "AudioSystem/SHAudioListenerComponent.h" #include "AudioSystem/SHAudioListenerComponent.h"
#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h"
#include "Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h"
#include "Camera/SHCameraSystem.h" #include "Camera/SHCameraSystem.h"
#include "FRC/SHFramerateController.h" #include "FRC/SHFramerateController.h"
@ -188,6 +189,10 @@ namespace SHADE
{ {
DrawComponent(trajectoryComponent); DrawComponent(trajectoryComponent);
} }
if (auto particleComponent = SHComponentManager::GetComponent_s<SHParticleEmitterComponent>(eid))
{
DrawComponent(particleComponent);
}
ImGui::Separator(); ImGui::Separator();
// Render Scripts // Render Scripts
SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>()); SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
@ -204,6 +209,7 @@ namespace SHADE
DrawAddComponentButton<SHToggleButtonComponent>(eid); DrawAddComponentButton<SHToggleButtonComponent>(eid);
DrawAddComponentButton<SHSliderComponent>(eid); DrawAddComponentButton<SHSliderComponent>(eid);
DrawAddComponentButton<SHTrajectoryRenderableComponent>(eid); DrawAddComponentButton<SHTrajectoryRenderableComponent>(eid);
DrawAddComponentButton<SHParticleEmitterComponent>(eid);
// Components that require Transforms // Components that require Transforms
@ -213,6 +219,7 @@ namespace SHADE
DrawAddComponentWithEnforcedComponentButton<SHTextRenderableComponent, SHTransformComponent>(eid); DrawAddComponentWithEnforcedComponentButton<SHTextRenderableComponent, SHTransformComponent>(eid);
DrawAddComponentWithEnforcedComponentButton<SHAnimatorComponent, SHTransformComponent, SHRenderable>(eid); DrawAddComponentWithEnforcedComponentButton<SHAnimatorComponent, SHTransformComponent, SHRenderable>(eid);
DrawAddComponentWithEnforcedComponentButton<SHAudioListenerComponent, SHTransformComponent>(eid); DrawAddComponentWithEnforcedComponentButton<SHAudioListenerComponent, SHTransformComponent>(eid);
//DrawAddComponentWithEnforcedComponentButton<SHParticleEmitterComponent, SHTransformComponent>(eid);
ImGui::EndMenu(); ImGui::EndMenu();
} }

View File

@ -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, uint32_t offset/* = 0*/)
{
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(), offset, drawCount, sizeof(vk::DrawIndirectCommand));
}
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);

View File

@ -128,9 +128,10 @@ namespace SHADE
void BindDescriptorSet (Handle<SHVkDescriptorSetGroup> descSetGroup, SH_PIPELINE_TYPE bindPoint, uint32_t firstSet, std::span<uint32_t> const dynamicOffsets); void BindDescriptorSet (Handle<SHVkDescriptorSetGroup> descSetGroup, SH_PIPELINE_TYPE bindPoint, uint32_t firstSet, std::span<uint32_t> const dynamicOffsets);
// 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 DrawMultiIndirect (Handle<SHVkBuffer> indirectDrawData, uint32_t drawCount); void DrawMultiIndirectIndexed (Handle<SHVkBuffer> indirectDrawData, uint32_t drawCount);
void DrawMultiIndirect (Handle<SHVkBuffer> indirectDrawData, uint32_t drawCount, uint32_t offset = 0);
// Compute Commands // Compute Commands
void ComputeDispatch (uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept; void ComputeDispatch (uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept;

View File

@ -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();
} }

View File

@ -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, // SSBO, 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,

View File

@ -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)

View File

@ -48,6 +48,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
#include "Input/SHInputManager.h" #include "Input/SHInputManager.h"
#include "Assets/Events/SHAssetManagerEvents.h" #include "Assets/Events/SHAssetManagerEvents.h"
#include "Graphics/MiddleEnd/Particles/SHParticleSubSystem.h"
namespace SHADE namespace SHADE
{ {
@ -144,6 +145,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 +170,10 @@ 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_FS = 42509714; particleFS = SHResourceManager::LoadOrGet<SHVkShaderModule>(PARTICLE_FS);
static constexpr AssetID PARTICLE_EMIT_CS = 49959611; particleEmitCS = SHResourceManager::LoadOrGet<SHVkShaderModule>(PARTICLE_EMIT_CS);
static constexpr AssetID PARTICLE_UPDATE_CS = 36260925; particleUpdateCS = SHResourceManager::LoadOrGet<SHVkShaderModule>(PARTICLE_UPDATE_CS);
} }
@ -343,11 +352,16 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
auto vfxPass = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::VFX_PASS.data(), { "Scene", "Depth Buffer" }, { SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data() }); auto vfxPass = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::VFX_PASS.data(), { "Scene", "Depth Buffer" }, { SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data() });
auto vfxSubpass = vfxPass->AddSubpass(SHGraphicsConstants::RenderGraphEntityNames::VFX_SUBPASS.data(), worldViewport, worldRenderer); auto vfxSubpass = vfxPass->AddSubpass(SHGraphicsConstants::RenderGraphEntityNames::VFX_SUBPASS.data(), worldViewport, worldRenderer);
//vfxPass->AddPreBeginFunction([=](Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex)
// {
// particleSubSystem->Run(cmdBuffer, frameIndex);
// });
vfxSubpass->AddColorOutput("Scene"); vfxSubpass->AddColorOutput("Scene");
vfxSubpass->AddDepthOutput("Depth Buffer"); vfxSubpass->AddDepthOutput("Depth Buffer");
vfxSubpass->AddExteriorDrawCalls([=](Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex) vfxSubpass->AddExteriorDrawCalls([=](Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex)
{ {
trajectoryRenderingSubSystem->Render(cmdBuffer, renderer, frameIndex); trajectoryRenderingSubSystem->Render(cmdBuffer, renderer, frameIndex);
particleSubSystem->Render(cmdBuffer, renderer, frameIndex);
}); });
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@ -490,6 +504,12 @@ namespace SHADE
trajectoryRenderingSubSystem = resourceManager.Create<SHTrajectoryRenderingSubSystem>(); trajectoryRenderingSubSystem = resourceManager.Create<SHTrajectoryRenderingSubSystem>();
auto vfxPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::VFX_PASS.data());
// particle sub system initialization
particleSubSystem = resourceManager.Create<SHParticleSubSystem>();
particleSubSystem->Init(device, descPool, vfxPass->GetRenderpass(), vfxPass->GetSubpass(SHGraphicsConstants::RenderGraphEntityNames::VFX_SUBPASS), particleVS, particleFS, particleEmitCS, particleUpdateCS);
auto vfxNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::VFX_PASS.data()); auto vfxNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::VFX_PASS.data());
trajectoryRenderingSubSystem->Init(device, vfxNode->GetRenderpass(), vfxNode->GetSubpass(SHGraphicsConstants::RenderGraphEntityNames::VFX_SUBPASS), trajectoryVS, trajectoryFS); trajectoryRenderingSubSystem->Init(device, vfxNode->GetRenderpass(), vfxNode->GetSubpass(SHGraphicsConstants::RenderGraphEntityNames::VFX_SUBPASS), trajectoryVS, trajectoryFS);
@ -669,7 +689,6 @@ namespace SHADE
textRenderingSubSystem->Run(frameIndex); textRenderingSubSystem->Run(frameIndex);
trajectoryRenderingSubSystem->Run(frameIndex); trajectoryRenderingSubSystem->Run(frameIndex);
for (auto renderer : renderers) for (auto renderer : renderers)
{ {
#ifdef SHEDITOR #ifdef SHEDITOR
@ -688,9 +707,12 @@ namespace SHADE
#endif #endif
} }
renderGraph->Begin(frameIndex); renderGraph->Begin(frameIndex);
auto cmdBuffer = renderGraph->GetCommandBuffer(frameIndex); auto cmdBuffer = renderGraph->GetCommandBuffer(frameIndex);
particleSubSystem->ResetInstanceCounts(cmdBuffer, frameIndex);
particleSubSystem->Run(cmdBuffer, frameIndex);
renderGraph->Execute(frameIndex, descPool, MESH_DATA); renderGraph->Execute(frameIndex, descPool, MESH_DATA);
renderGraph->End(frameIndex); renderGraph->End(frameIndex);

View File

@ -59,6 +59,7 @@ namespace SHADE
class SHMaterialInstance; class SHMaterialInstance;
class SHMousePickSystem; class SHMousePickSystem;
class SHTextRenderingSubSystem; class SHTextRenderingSubSystem;
class SHParticleSubSystem;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
@ -484,6 +485,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;
@ -523,6 +528,7 @@ namespace SHADE
Handle<SHLightingSubSystem> lightingSubSystem; Handle<SHLightingSubSystem> lightingSubSystem;
Handle<SHTextRenderingSubSystem> textRenderingSubSystem; Handle<SHTextRenderingSubSystem> textRenderingSubSystem;
Handle<SHTrajectoryRenderingSubSystem> trajectoryRenderingSubSystem; Handle<SHTrajectoryRenderingSubSystem> trajectoryRenderingSubSystem;
Handle<SHParticleSubSystem> particleSubSystem;
Handle<SHSSAO> ssaoStorage; Handle<SHSSAO> ssaoStorage;
uint32_t resizeWidth = 1; uint32_t resizeWidth = 1;

View File

@ -20,4 +20,178 @@ namespace SHADE
toEmit = true; toEmit = true;
} }
void SHParticleEmitterComponent::SetEmissionCount(uint32_t count) noexcept
{
emissionCount = count;
}
void SHParticleEmitterComponent::SetPassive(bool flag) noexcept
{
isPassive = flag;
}
void SHParticleEmitterComponent::SetEmissionInterval(float interval) noexcept
{
emissionInterval = interval;
timeBeforeEmission = emissionInterval;
}
void SHParticleEmitterComponent::SetMinLife(float val) noexcept
{
cpuEmitterData.lifeAndSizeRange.x = val;
}
void SHParticleEmitterComponent::SetMaxLife(float val) noexcept
{
cpuEmitterData.lifeAndSizeRange.y = val;
}
void SHParticleEmitterComponent::SetAngularRangesAndOffsets(SHVec4 const& ranges) noexcept
{
cpuEmitterData.angularRangesAndOffsets = SHVec4 (ranges);
}
void SHParticleEmitterComponent::SetMinSpeed(float speed) noexcept
{
cpuEmitterData.minSpeed = speed;
}
void SHParticleEmitterComponent::SetMaxSpeed(float speed) noexcept
{
cpuEmitterData.maxSpeed = speed;
}
void SHParticleEmitterComponent::SetRotationSpeed(float speed) noexcept
{
cpuEmitterData.rotationSpeed = speed;
}
void SHParticleEmitterComponent::SetRotationDecay(float decay) noexcept
{
cpuEmitterData.rotationDecay = decay;
}
void SHParticleEmitterComponent::SetTextureIndex(uint32_t index) noexcept
{
cpuEmitterData.textureIndex = index;
}
void SHParticleEmitterComponent::SetTextureAssetID(AssetID id) noexcept
{
textureAssetID = id;
}
void SHParticleEmitterComponent::SetCustomUpdateShaderAssetID(AssetID id) noexcept
{
customUpdateShaderID = id;
}
void SHParticleEmitterComponent::SetMinSize(float size) noexcept
{
cpuEmitterData.lifeAndSizeRange.z = size;
}
void SHParticleEmitterComponent::SetMaxSize(float size) noexcept
{
cpuEmitterData.lifeAndSizeRange.w = size;
}
void SHParticleEmitterComponent::SetSizeDecayMult(float decay) noexcept
{
cpuEmitterData.sizeDecayMult = decay;
}
void SHParticleEmitterComponent::SetCustomUpdateShader(Handle<SHVkShaderModule> shaderModule) noexcept
{
customUpdateShader = shaderModule;
}
uint32_t SHParticleEmitterComponent::GetEmissionCount(void) const noexcept
{
return emissionCount;
}
bool SHParticleEmitterComponent::GetPassive(void) const noexcept
{
return isPassive;
}
float SHParticleEmitterComponent::GetEmissionInterval(void) const noexcept
{
return emissionInterval;
}
float SHParticleEmitterComponent::GetMinLife(void) const noexcept
{
return cpuEmitterData.lifeAndSizeRange.x;
}
float SHParticleEmitterComponent::GetMaxLife(void) const noexcept
{
return cpuEmitterData.lifeAndSizeRange.y;
}
SHVec4 const& SHParticleEmitterComponent::GetAngularRangesAndOffsets(void) const noexcept
{
return cpuEmitterData.angularRangesAndOffsets;
}
float SHParticleEmitterComponent::GetMinSpeed(void) const noexcept
{
return cpuEmitterData.minSpeed;
}
float SHParticleEmitterComponent::GetMaxSpeed(void) const noexcept
{
return cpuEmitterData.maxSpeed;
}
float SHParticleEmitterComponent::GetRotationSpeed(void) const noexcept
{
return cpuEmitterData.rotationSpeed;
}
float SHParticleEmitterComponent::GetRotationDecay(void) const noexcept
{
return cpuEmitterData.rotationDecay;
}
uint32_t SHParticleEmitterComponent::GetTextureIndex(void) const noexcept
{
return cpuEmitterData.textureIndex;
}
AssetID SHParticleEmitterComponent::GetTextureAssetID(void) const noexcept
{
return textureAssetID;
}
AssetID SHParticleEmitterComponent::GetCustomUpdateShaderAssetID(void) const noexcept
{
return customUpdateShaderID;
}
float SHParticleEmitterComponent::GetMinSize(void) const noexcept
{
return cpuEmitterData.lifeAndSizeRange.z;
}
float SHParticleEmitterComponent::GetMaxSize(void) const noexcept
{
return cpuEmitterData.lifeAndSizeRange.w;
}
float SHParticleEmitterComponent::GetSizeDecayMult(void) const noexcept
{
return cpuEmitterData.sizeDecayMult;
}
Handle<SHVkShaderModule> SHParticleEmitterComponent::GetCustomUpdateShader(void) const noexcept
{
return customUpdateShader;
}
} }

View File

@ -1,29 +1,53 @@
#pragma once #pragma once
#include "Resource/SHHandle.h" #include "Resource/SHHandle.h"
#include "Math/Vector/SHVec2.h"
#include "Math/Vector/SHVec4.h" #include "Math/Vector/SHVec4.h"
#include "ECS_Base/Components/SHComponent.h" #include "ECS_Base/Components/SHComponent.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h" #include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
#include <Assets/SHAssetMacros.h>
namespace SHADE namespace SHADE
{ {
class SHVkBuffer; class SHVkBuffer;
class SHVkDescriptorSetGroup; class SHVkDescriptorSetGroup;
class SHVkDescriptorSetLayout; class SHVkDescriptorSetLayout;
class SHVkShaderModule;
class SHVkPipeline;
class SHParticleEmitterComponent : public SHComponent class SHParticleEmitterComponent : public SHComponent
{ {
private: private:
struct GPUEmitterStruct struct GPUEmitterStruct
{ {
//! Minimum emitting angular range //! Angular ranges of emission
SHVec4 angularMin; SHVec4 angularRangesAndOffsets;
//! Maximum emitting angular range //! minimum starting velocity
SHVec4 angularMax; float minSpeed;
//! Maximum starting velocity
float maxSpeed;
//! Rotational speed of the quad
float rotationSpeed;
//! Rotation decay rate
float rotationDecay;
//! Spawn lifetime and size range (min and max) //! Spawn lifetime and size range (min and max)
SHVec4 lifeAndSizeRange; SHVec4 lifeAndSizeRange;
//! Size decay for particles
float sizeDecayMult;
//! Texture used by the particle
uint32_t textureIndex;
//! Padding for the shader struct
float padding[2];
}; };
struct GPUParticleStruct struct GPUParticleStruct
@ -84,6 +108,12 @@ namespace SHADE
//! will contain 2 bindings that point to 2 buffers (input and output). //! will contain 2 bindings that point to 2 buffers (input and output).
Handle<SHVkDescriptorSetGroup> particleDescriptorSet; Handle<SHVkDescriptorSetGroup> particleDescriptorSet;
//! Custom update shader for the particles in this component
Handle<SHVkShaderModule> customUpdateShader;
//! Internally the system will bind this pipeline when it detects that this is not a null handle
Handle<SHVkPipeline> customUpdatePipeline;
//! Emitter's data on the CPU side. To be copied to GPU. //! Emitter's data on the CPU side. To be copied to GPU.
GPUEmitterStruct cpuEmitterData; GPUEmitterStruct cpuEmitterData;
@ -99,12 +129,60 @@ namespace SHADE
//! For all the dynamic SSBOs in the descriptor set //! For all the dynamic SSBOs in the descriptor set
std::array<std::array<uint32_t, 5>, SHGraphicsConstants::NUM_FRAME_BUFFERS> dynamicOffsets{}; std::array<std::array<uint32_t, 5>, SHGraphicsConstants::NUM_FRAME_BUFFERS> dynamicOffsets{};
//! For the emitter to use to give particles their texture
AssetID textureAssetID;
//! Custom update shaders, similarly with textures, will be identified through their AssetID
AssetID customUpdateShaderID;
public: public:
void OnCreate(void) override final; void OnCreate(void) override final;
void OnDestroy(void) override final; void OnDestroy(void) override final;
void Emit (void) noexcept; void Emit (void) noexcept;
void SetEmissionCount (uint32_t count) noexcept;
void SetPassive (bool flag) noexcept;
void SetEmissionInterval (float interval) noexcept;
void SetMinLife (float val) noexcept;
void SetMaxLife (float val) noexcept;
void SetAngularRangesAndOffsets (SHVec4 const& ranges) noexcept;
void SetMinSpeed (float speed) noexcept;
void SetMaxSpeed (float speed) noexcept;
void SetRotationSpeed (float speed) noexcept;
void SetRotationDecay (float decay) noexcept;
void SetTextureIndex (uint32_t index) noexcept;
void SetMinSize (float size) noexcept;
void SetMaxSize (float size) noexcept;
void SetSizeDecayMult (float decay) noexcept;
void SetCustomUpdateShader (Handle<SHVkShaderModule> shaderModule) noexcept;
uint32_t GetEmissionCount (void) const noexcept;
bool GetPassive (void) const noexcept;
float GetEmissionInterval (void) const noexcept;
float GetMinLife (void) const noexcept;
float GetMaxLife (void) const noexcept;
SHVec4 const& GetAngularRangesAndOffsets (void) const noexcept;
float GetMinSpeed (void) const noexcept;
float GetMaxSpeed (void) const noexcept;
float GetRotationSpeed (void) const noexcept;
float GetRotationDecay (void) const noexcept;
uint32_t GetTextureIndex (void) const noexcept;
float GetMinSize (void) const noexcept;
float GetMaxSize (void) const noexcept;
float GetSizeDecayMult (void) const noexcept;
Handle<SHVkShaderModule> GetCustomUpdateShader (void) const noexcept;
/*-----------------------------------------------------------------------*/
/* NON-INTERFACE FUNCTIONS */
/*-----------------------------------------------------------------------*/
void SetTextureAssetID(AssetID id) noexcept;
void SetCustomUpdateShaderAssetID(AssetID id) noexcept;
AssetID GetTextureAssetID(void) const noexcept;
AssetID GetCustomUpdateShaderAssetID(void) const noexcept;
friend class SHParticleSubSystem; friend class SHParticleSubSystem;
}; };

View File

@ -10,29 +10,39 @@
#include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h" #include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
#include "Graphics/Buffers/SHVkBuffer.h" #include "Graphics/Buffers/SHVkBuffer.h"
#include "FRC/SHFramerateController.h"
#include "Graphics/Pipeline/SHVkPipeline.h"
#include "Graphics/RenderGraph/SHSubpass.h"
#include "Graphics/SHVkUtil.h"
#include "Graphics/Synchronization/SHVkFence.h"
namespace SHADE namespace SHADE
{ {
void SHParticleSubSystem::InitializeComponent(SHParticleEmitterComponent& comp) noexcept 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<uint32_t>(sizeof(vk::DrawIndirectCommand));
uint32_t sizeofUint = static_cast<uint32_t>(sizeof(uint32_t));
// TODO: temporary only. // TODO: temporary only.
static constexpr uint32_t NUM_PARTICLES = 500; static constexpr uint32_t NUM_PARTICLES = 2000;
comp.maxParticles = NUM_PARTICLES; comp.maxParticles = NUM_PARTICLES;
uint32_t sizeofUint = static_cast<uint32_t>(sizeof(uint32_t));
uint32_t sizeofIndirectCmdAligned = logicalDevice->PadSSBOSize(sizeof(vk::DrawIndirectCommand));
uint32_t emitterStructAligned = logicalDevice->PadSSBOSize(sizeof (SHParticleEmitterComponent::GPUEmitterStruct));
uint32_t particleChunkStructAligned = logicalDevice->PadSSBOSize(sizeof (SHParticleEmitterComponent::GPUParticleStruct)) * comp.maxParticles;
uint32_t indicesDataAligned = logicalDevice->PadSSBOSize(sizeofUint * comp.maxParticles);
// offset into the buffer for input and output // offset into the buffer for input and output
uint32_t const PARTICLE_FRAME_CHUNK_SIZE = (particleStructAligned * comp.maxParticles); uint32_t const PARTICLE_FRAME_CHUNK_SIZE = particleChunkStructAligned;
// Buffer Initialization // Buffer Initialization
{ {
// count, value // count, value. Initialize free count to max particles and indices to particle indices
std::vector<uint32_t> freelistInit(comp.maxParticles + 1, 0); std::vector<uint32_t> freelistInit(comp.maxParticles + 1, 0);
freelistInit[0] = comp.maxParticles; freelistInit[0] = comp.maxParticles;
for (uint32_t i = 0; i < comp.maxParticles; ++i)
freelistInit[i + 1] = i;
// 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 // 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. // is using it during compute operations so we write to another portion.
@ -40,14 +50,14 @@ namespace SHADE
// 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 // 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 // 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, {}); comp.particleData = logicalDevice->CreateBuffer(SHGraphicsConstants::NUM_FRAME_BUFFERS * particleChunkStructAligned, 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 // 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. // 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); 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. // 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); comp.indicesData = logicalDevice->CreateBuffer(SHGraphicsConstants::NUM_FRAME_BUFFERS * indicesDataAligned, 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 // 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<vk::DrawIndirectCommand, SHGraphicsConstants::NUM_FRAME_BUFFERS> indirectCommands{}; std::array<vk::DrawIndirectCommand, SHGraphicsConstants::NUM_FRAME_BUFFERS> indirectCommands{};
@ -60,7 +70,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 * sizeofIndirectCmdAligned, indirectCommands.data(), SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmdAligned, vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndirectBuffer, VMA_MEMORY_USAGE_AUTO, VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT);
} }
@ -73,7 +83,7 @@ namespace SHADE
static constexpr uint32_t PARTICLE_DATA_SET_INDEX = 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. ) // 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}; std::vector const VARIABLE_COUNTS = {0u};
// allocate new desc set // allocate new desc set
comp.particleDescriptorSet = descPool->Allocate(descSetLayout, VARIABLE_COUNTS); comp.particleDescriptorSet = descPool->Allocate(descSetLayout, VARIABLE_COUNTS);
@ -83,11 +93,18 @@ namespace SHADE
// After buffers are created, we want to populate all bindings(6) with the buffers // 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_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_INPUT_DATA, { &comp.particleData, 1 }, 0, particleChunkStructAligned); // 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_OUTPUT_DATA, { &comp.particleData, 1 }, 0, particleChunkStructAligned);
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_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_INDICES_DATA, { &comp.indicesData, 1 }, 0, indicesDataAligned);
set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_DRAW_DATA, { &comp.drawCallData, 1 }, 0, sizeofIndirectCmd); set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_DRAW_DATA, { &comp.drawCallData, 1 }, 0, sizeofIndirectCmdAligned);
set->UpdateDescriptorSetBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_EMITTER_DATA);
set->UpdateDescriptorSetBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INPUT_DATA);
set->UpdateDescriptorSetBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_OUTPUT_DATA);
set->UpdateDescriptorSetBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_FREELIST_DATA);
set->UpdateDescriptorSetBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INDICES_DATA);
set->UpdateDescriptorSetBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_DRAW_DATA);
} }
comp.initialized = true; comp.initialized = true;
@ -110,8 +127,8 @@ namespace SHADE
offsets[DYOFF_INDEX_EMITTER] = i * emitterStructAligned; offsets[DYOFF_INDEX_EMITTER] = i * emitterStructAligned;
offsets[DYOFF_INDEX_PARTICLE_INPUT] = inputOffset; offsets[DYOFF_INDEX_PARTICLE_INPUT] = inputOffset;
offsets[DYOFF_INDEX_PARTICLE_OUTPUT] = outputOffset; offsets[DYOFF_INDEX_PARTICLE_OUTPUT] = outputOffset;
offsets[DYOFF_INDEX_INDICES_DATA] = i * sizeofUint * comp.maxParticles; offsets[DYOFF_INDEX_INDICES_DATA] = i * indicesDataAligned;
offsets[DYOFF_INDEX_DRAW_DATA] = i * sizeofIndirectCmd; offsets[DYOFF_INDEX_DRAW_DATA] = i * sizeofIndirectCmdAligned;
} }
} }
@ -126,6 +143,8 @@ namespace SHADE
cmdBuffer->SetPushConstantVariable("EmitterPushConstant.emitterPosition", transform->GetWorldPosition(), SH_PIPELINE_TYPE::COMPUTE); cmdBuffer->SetPushConstantVariable("EmitterPushConstant.emitterPosition", transform->GetWorldPosition(), SH_PIPELINE_TYPE::COMPUTE);
cmdBuffer->SetPushConstantVariable("EmitterPushConstant.emissionCount", comp.emissionCount, SH_PIPELINE_TYPE::COMPUTE); cmdBuffer->SetPushConstantVariable("EmitterPushConstant.emissionCount", comp.emissionCount, SH_PIPELINE_TYPE::COMPUTE);
cmdBuffer->SubmitPushConstants(SH_PIPELINE_TYPE::COMPUTE);
// emit particles // emit particles
cmdBuffer->ComputeDispatch((comp.emissionCount / EMITTER_WORKGROUP_SIZE) + 1, 1, 1); cmdBuffer->ComputeDispatch((comp.emissionCount / EMITTER_WORKGROUP_SIZE) + 1, 1, 1);
} }
@ -134,13 +153,6 @@ namespace SHADE
{ {
auto const& mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING); 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 // bind the descriptor sets required for emitting particles
cmdBuffer->BindDescriptorSet(comp.particleDescriptorSet, SH_PIPELINE_TYPE::COMPUTE, mappings.at(SHPredefinedDescriptorTypes::PARTICLES), comp.dynamicOffsets[frameIndex]); cmdBuffer->BindDescriptorSet(comp.particleDescriptorSet, SH_PIPELINE_TYPE::COMPUTE, mappings.at(SHPredefinedDescriptorTypes::PARTICLES), comp.dynamicOffsets[frameIndex]);
@ -150,7 +162,110 @@ 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, static_cast<uint32_t>(sizeof(vk::DrawIndirectCommand)) * frameIndex);
//cmdBuffer->DrawArrays(4, 1, 0, 0);
}
void SHParticleSubSystem::PreparePrePostUpdateBarriers(std::vector<vk::BufferMemoryBarrier>& preUpdateBarriers, std::vector<vk::BufferMemoryBarrier>& postUpdateBarriers, SHParticleEmitterComponent const& emitter, uint32_t const EMITTER_INDEX, uint32_t const FRAME_INDEX) noexcept
{
// 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 inputParticleDataBarrierPreUpdate
{
.srcAccessMask = vk::AccessFlagBits::eShaderRead | 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 freelistDataBarrierPreUpdate
{
.srcAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite,
.dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite,
.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)
};
// pre update indices data barrier.
vk::BufferMemoryBarrier indicesDataBarrierPreUpdate
{
.srcAccessMask = vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eShaderRead,
.dstAccessMask = vk::AccessFlagBits::eShaderWrite,
.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
preUpdateBarriers.push_back(inputParticleDataBarrierPreUpdate);
preUpdateBarriers.push_back(freelistDataBarrierPreUpdate);
preUpdateBarriers.push_back(indicesDataBarrierPreUpdate);
// make new barrier on stack...
vk::BufferMemoryBarrier outputParticleDataBarrierPostUpdate
{
.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 indicesDataBarrierPostUpdate
{
.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
};
// make new barrier on stack...
vk::BufferMemoryBarrier drawDataBarrierPostUpdate
{
.srcAccessMask = vk::AccessFlagBits::eShaderWrite,
.dstAccessMask = vk::AccessFlagBits::eIndirectCommandRead,
.buffer = emitter.drawCallData->GetVkBuffer(),
.offset = emitter.dynamicOffsets[FRAME_INDEX][DYOFF_INDEX_DRAW_DATA],
.size = static_cast<uint32_t>(sizeof(vk::DrawIndirectCommand))
};
// ...copy assign barriers on heap
postUpdateBarriers.push_back(outputParticleDataBarrierPostUpdate);
postUpdateBarriers.push_back(indicesDataBarrierPostUpdate);
postUpdateBarriers.push_back(drawDataBarrierPostUpdate);
}
Handle<SHVkPipeline> SHParticleSubSystem::GetCustomUpdatePipeline(Handle<SHVkShaderModule> customUpdateShader) noexcept
{
if (!customUpdateShader)
return {};
if (!customUpdatePipelineCache.contains(customUpdateShader))
{
SHPipelineLayoutParams plParams
{
.shaderModules = {customUpdateShader},
.predefinedDescSetLayouts = SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING).descSetLayouts
};
auto pipelineLayout = logicalDevice->CreatePipelineLayout(plParams);
auto newPipeline = logicalDevice->CreateComputePipeline(pipelineLayout);
newPipeline->ConstructPipeline();
if (!newPipeline)
return {};
auto customUpdateShaderData = CustomPipeline{ newPipeline, pipelineLayout };
customUpdatePipelineCache.emplace (customUpdateShader, customUpdateShaderData);
}
return customUpdatePipelineCache.at (customUpdateShader).customPipeline;
} }
void SHParticleSubSystem::Init(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> inDescPool, Handle<SHVkRenderpass> compatibleRenderpass, Handle<SHSubpass> subpass, Handle<SHVkShaderModule> VS, Handle<SHVkShaderModule> FS, Handle<SHVkShaderModule> emitCS, Handle<SHVkShaderModule> defaultUpdateCS) noexcept void SHParticleSubSystem::Init(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> inDescPool, Handle<SHVkRenderpass> compatibleRenderpass, Handle<SHSubpass> subpass, Handle<SHVkShaderModule> VS, Handle<SHVkShaderModule> FS, Handle<SHVkShaderModule> emitCS, Handle<SHVkShaderModule> defaultUpdateCS) noexcept
@ -170,6 +285,40 @@ namespace SHADE
renderingPipelineData.pipelineLayout = logicalDevice->CreatePipelineLayout(plParams); renderingPipelineData.pipelineLayout = logicalDevice->CreatePipelineLayout(plParams);
renderingPipelineData.pipeline = logicalDevice->CreateGraphicsPipeline(renderingPipelineData.pipelineLayout, nullptr, compatibleRenderpass, subpass); renderingPipelineData.pipeline = logicalDevice->CreateGraphicsPipeline(renderingPipelineData.pipelineLayout, nullptr, compatibleRenderpass, subpass);
SHColorBlendState colorBlendState{};
colorBlendState.logic_op_enable = VK_FALSE;
colorBlendState.logic_op = vk::LogicOp::eCopy;
auto const& subpassColorReferences = subpass->GetColorAttachmentReferences();
colorBlendState.attachments.reserve(subpassColorReferences.size());
for (auto& att : subpassColorReferences)
{
colorBlendState.attachments.push_back(vk::PipelineColorBlendAttachmentState
{
.blendEnable = SHVkUtil::IsBlendCompatible(subpass->GetFormatFromAttachmentReference(att.attachment)),
.srcColorBlendFactor = vk::BlendFactor::eSrcAlpha,
.dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha,
.colorBlendOp = vk::BlendOp::eAdd,
.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,
}
);
}
renderingPipelineData.pipeline->GetPipelineState().SetColorBlenState(colorBlendState);
// Sets the input assembly state for rendering particles
SHInputAssemblyState inputAssemblyState{};
inputAssemblyState.topology = vk::PrimitiveTopology::eTriangleFan;
renderingPipelineData.pipeline->GetPipelineState().SetInputAssemblyState(inputAssemblyState);
renderingPipelineData.pipeline->ConstructPipeline();
SHPipelineLayoutParams emitPlParams SHPipelineLayoutParams emitPlParams
{ {
.shaderModules = {emitCS}, .shaderModules = {emitCS},
@ -178,6 +327,7 @@ namespace SHADE
emittingPipelineData.pipelineLayout = logicalDevice->CreatePipelineLayout(emitPlParams); emittingPipelineData.pipelineLayout = logicalDevice->CreatePipelineLayout(emitPlParams);
emittingPipelineData.pipeline = logicalDevice->CreateComputePipeline(emittingPipelineData.pipelineLayout); emittingPipelineData.pipeline = logicalDevice->CreateComputePipeline(emittingPipelineData.pipelineLayout);
emittingPipelineData.pipeline->ConstructPipeline();
SHPipelineLayoutParams defaultUpdatePlParams SHPipelineLayoutParams defaultUpdatePlParams
{ {
@ -187,7 +337,7 @@ namespace SHADE
defaultUpdatePipelineData.pipelineLayout = logicalDevice->CreatePipelineLayout(defaultUpdatePlParams); defaultUpdatePipelineData.pipelineLayout = logicalDevice->CreatePipelineLayout(defaultUpdatePlParams);
defaultUpdatePipelineData.pipeline = logicalDevice->CreateComputePipeline(defaultUpdatePipelineData.pipelineLayout); defaultUpdatePipelineData.pipeline = logicalDevice->CreateComputePipeline(defaultUpdatePipelineData.pipelineLayout);
defaultUpdatePipelineData.pipeline->ConstructPipeline();
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* OTHER INITIALIZATION */ /* OTHER INITIALIZATION */
@ -195,18 +345,33 @@ namespace SHADE
SHComponentManager::CreateComponentSparseSet<SHParticleEmitterComponent>(); SHComponentManager::CreateComponentSparseSet<SHParticleEmitterComponent>();
} }
void SHParticleSubSystem::Run(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, float dt) noexcept void SHParticleSubSystem::Run(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, Handle<SHVkFence> waitFence) noexcept
{ {
float dt = static_cast<float>(SHFrameRateController::GetRawDeltaTime());
auto& emitters = SHComponentManager::GetDense<SHParticleEmitterComponent>(); auto& emitters = SHComponentManager::GetDense<SHParticleEmitterComponent>();
auto const& mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING); auto const& mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING);
// 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.reserve(emitters.size() * 3);
// 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.reserve(emitters.size() * 3);
std::vector<vk::BufferMemoryBarrier> preDrawBarriers{};
preDrawBarriers.reserve(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 // 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.
@ -215,8 +380,6 @@ namespace SHADE
/* BEGIN EMITTING PARTICES */ /* BEGIN EMITTING PARTICES */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
// TODO: Might need to issue a barrier here for input particle data
// bind the pipeline for emitting particles // bind the pipeline for emitting particles
cmdBuffer->BindPipeline(emittingPipelineData.pipeline); cmdBuffer->BindPipeline(emittingPipelineData.pipeline);
@ -224,83 +387,135 @@ namespace SHADE
SHGlobalDescriptorSets::BindGenericAndTextureData(logicalDevice, cmdBuffer, SH_PIPELINE_TYPE::COMPUTE, mappings.at(SHPredefinedDescriptorTypes::STATIC_DATA), frameIndex); SHGlobalDescriptorSets::BindGenericAndTextureData(logicalDevice, cmdBuffer, SH_PIPELINE_TYPE::COMPUTE, mappings.at(SHPredefinedDescriptorTypes::STATIC_DATA), frameIndex);
uint32_t i = 0; uint32_t i = 0;
if (waitFence)
waitFence->Wait(true);
for (auto& emitter : emitters) for (auto& emitter : emitters)
{ {
if (!emitter.initialized) if (emitter.isActive)
InitializeComponent(emitter);
// Set emitter emit flag to true here if there are ready to be emitted
if (emitter.isPassive)
{ {
// decrement emission timer if (!emitter.initialized)
emitter.timeBeforeEmission -= dt; InitializeComponent(emitter);
// Check if time to emit // Set emitter emit flag to true here if there are ready to be emitted
if (emitter.timeBeforeEmission <= 0.0f) if (emitter.isPassive)
{ {
// reset timer // decrement emission timer
emitter.timeBeforeEmission = emitter.emissionInterval; emitter.timeBeforeEmission -= dt;
// Emit later // Check if time to emit
emitter.toEmit = true; 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);
}
// 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;
} }
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; ++i;
} }
// issue the barrier to wait // issue the barrier to wait
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {}, preUpdateBarriers, {}); if (!preUpdateBarriers.empty())
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eDrawIndirect, vk::PipelineStageFlagBits::eComputeShader, {}, {}, preUpdateBarriers, {});
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* EMITTING PARTICLES DONE, BEGIN UPDATES.... */ /* EMITTING PARTICLES DONE, BEGIN UPDATES.... */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
for (auto& emitter : emitters)
{
// If custom update shader is a valid handle in the component
if (emitter.customUpdateShader)
{
// Check if pipeline associated with shader is valid, if not create or get one from the cache
if (!emitter.customUpdatePipeline)
emitter.customUpdatePipeline = GetCustomUpdatePipeline(emitter.customUpdateShader);
// bind the pipeline for updating // bind the custom pipeline for updating
cmdBuffer->BindPipeline(defaultUpdatePipelineData.pipeline); cmdBuffer->BindPipeline(emitter.customUpdatePipeline);
}
else
{
// bind the default upddate pipeline for updating
cmdBuffer->BindPipeline(defaultUpdatePipelineData.pipeline);
}
if (emitter.isActive)
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.
if (!postUpdateBarriers.empty())
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eDrawIndirect | vk::PipelineStageFlagBits::eVertexShader, {}, {}, postUpdateBarriers, {});
}
void SHParticleSubSystem::ResetInstanceCounts(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
{
auto& emitters = SHComponentManager::GetDense<SHParticleEmitterComponent>();
for (auto& emitter : emitters) for (auto& emitter : emitters)
{ {
UpdateCompoennt(cmdBuffer, emitter, frameIndex); if (emitter.initialized)
{
//uint32_t instanceCountOffset = 20;
uint32_t instanceCountOffset = sizeof(vk::DrawIndirectCommand) * frameIndex + offsetof(vk::DrawIndirectCommand, instanceCount);
uint32_t ZERO = 0;
// reset instance count to 0
emitter.drawCallData->WriteToMemory(&ZERO, sizeof(uint32_t), 0, instanceCountOffset);
}
} }
} }
void SHParticleSubSystem::Render(Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex) noexcept void SHParticleSubSystem::Render(Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex) noexcept
{ {
auto& emitters = SHComponentManager::GetDense<SHParticleEmitterComponent>(); auto& emitters = SHComponentManager::GetDense<SHParticleEmitterComponent>();
auto const& mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING);
// bind the pipeline for updating
cmdBuffer->BindPipeline(renderingPipelineData.pipeline);
// 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)
{ {
if (emitter.isActive)
{
// bind the descriptor sets required for emitting particles
cmdBuffer->BindDescriptorSet(emitter.particleDescriptorSet, SH_PIPELINE_TYPE::GRAPHICS, mappings.at(SHPredefinedDescriptorTypes::PARTICLES), emitter.dynamicOffsets[frameIndex]);
RenderComponent(cmdBuffer, emitter, frameIndex);
}
} }
} }
void SHParticleSubSystem::Exit(void) noexcept void SHParticleSubSystem::Exit(void) noexcept
{ {

View File

@ -20,6 +20,7 @@ namespace SHADE
class SHVkShaderModule; class SHVkShaderModule;
class SHRenderer; class SHRenderer;
class SHParticleEmitterComponent; class SHParticleEmitterComponent;
class SHVkFence;
@ -33,6 +34,12 @@ namespace SHADE
static constexpr uint32_t DYOFF_INDEX_INDICES_DATA = 3; static constexpr uint32_t DYOFF_INDEX_INDICES_DATA = 3;
static constexpr uint32_t DYOFF_INDEX_DRAW_DATA = 4; static constexpr uint32_t DYOFF_INDEX_DRAW_DATA = 4;
struct CustomPipeline
{
Handle<SHVkPipeline> customPipeline;
Handle<SHVkPipelineLayout> customPipelineLayout;
};
// To hold data for a pipeline and pipeline layout. // To hold data for a pipeline and pipeline layout.
// We want this here because particles require 3 pipeline sets: // We want this here because particles require 3 pipeline sets:
@ -75,16 +82,23 @@ namespace SHADE
//! Desc pool for particle component desc set allocation //! Desc pool for particle component desc set allocation
Handle<SHVkDescriptorPool> descPool; Handle<SHVkDescriptorPool> descPool;
std::unordered_map<Handle<SHVkShaderModule>, CustomPipeline> customUpdatePipelineCache;
void InitializeComponent (SHParticleEmitterComponent& comp) noexcept; void InitializeComponent (SHParticleEmitterComponent& comp) noexcept;
void EmitComponent (Handle<SHVkCommandBuffer> cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept; void EmitComponent (Handle<SHVkCommandBuffer> cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept;
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;
Handle<SHVkPipeline> GetCustomUpdatePipeline (Handle<SHVkShaderModule> customUpdateShader) 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;
void Run(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, float dt) noexcept; void Run(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, Handle<SHVkFence> waitFence = {}) noexcept;
void ResetInstanceCounts (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
void Render(Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex) noexcept; void Render(Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex) noexcept;
void Exit(void) noexcept; void Exit(void) noexcept;

View File

@ -19,15 +19,16 @@ namespace SHADE
// generate samples // generate samples
for (uint32_t i = 0; i < NUM_SAMPLES; ++i) for (uint32_t i = 0; i < NUM_SAMPLES; ++i)
{ {
//SHVec3 temp SHVec3 temp
//{ {
// distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
// distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
// distrib(generator), // 0.0f - 1.0f so that sample space is a hemisphere distrib(generator), // 0.0f - 1.0f so that sample space is a hemisphere
//}; };
//temp = SHVec3::Normalise(temp); temp = SHVec3::Normalise(temp);
//temp *= distrib(generator); temp *= distrib(generator);
samples[i] = SHVec4 (temp.x, temp.y, temp.z, 0.0f);
//// This makes sure that most points are closer to fragment's position //// This makes sure that most points are closer to fragment's position
//float scale = 1.0f / static_cast<float>(NUM_SAMPLES); //float scale = 1.0f / static_cast<float>(NUM_SAMPLES);
@ -36,16 +37,16 @@ namespace SHADE
//samples[i] = SHVec4 (temp.x, temp.y, temp.z, 0.0f); //samples[i] = SHVec4 (temp.x, temp.y, temp.z, 0.0f);
samples[i] = SHVec4 //samples[i] = SHVec4
{ //{
distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f // distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f // distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
distrib(generator), // 0.0f - 1.0f so that sample space is a hemisphere // distrib(generator), // 0.0f - 1.0f so that sample space is a hemisphere
0.0f // 0.0f
}; //};
// This makes sure that most points are closer to fragment's position // This makes sure that most points are closer to fragment's position
float scale = 1.0f / static_cast<float>(NUM_SAMPLES); float scale = static_cast<float>(i) / static_cast<float>(NUM_SAMPLES);
scale = std::lerp(0.1f, 1.0f, scale * scale); scale = std::lerp(0.1f, 1.0f, scale * scale);
samples[i] *= scale; samples[i] *= scale;
} }

View File

@ -14,6 +14,7 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
void SHTrajectoryRenderableComponent::OnCreate(void) void SHTrajectoryRenderableComponent::OnCreate(void)
{ {
ResetSimulationInfo();
} }
void SHTrajectoryRenderableComponent::OnDestroy(void) void SHTrajectoryRenderableComponent::OnDestroy(void)
@ -22,12 +23,13 @@ namespace SHADE
} }
void SHTrajectoryRenderableComponent::SimulateTrajectory(EntityID eid, SHVec3 force, float timestep, uint32_t maxSteps) noexcept void SHTrajectoryRenderableComponent::SimulateTrajectory(EntityID eid, float mass, SHVec3 force, float timestep, uint32_t maxSteps) noexcept
{ {
entityToSimulate = eid; entityToSimulate = eid;
simulationForce = force; simulationForce = force;
simulationTimestep = timestep; simulationTimestep = timestep;
simulationMaxSteps = maxSteps; simulationMaxSteps = maxSteps;
objectMass = mass;
} }
float SHTrajectoryRenderableComponent::GetSimulationTimestep(void) const noexcept float SHTrajectoryRenderableComponent::GetSimulationTimestep(void) const noexcept
@ -35,6 +37,11 @@ namespace SHADE
return simulationTimestep; return simulationTimestep;
} }
float SHTrajectoryRenderableComponent::GetObjectMass(void) const noexcept
{
return objectMass;
}
void SHTrajectoryRenderableComponent::ResetSimulationInfo(void) noexcept void SHTrajectoryRenderableComponent::ResetSimulationInfo(void) noexcept
{ {
entityToSimulate = MAX_EID; entityToSimulate = MAX_EID;

View File

@ -36,6 +36,9 @@ namespace SHADE
//! plotting a point in the simulation //! plotting a point in the simulation
float simulationTimestep; float simulationTimestep;
//! mass of the object to simulate
float objectMass;
//! Entity to simulate trajectory of //! Entity to simulate trajectory of
EntityID entityToSimulate; EntityID entityToSimulate;
@ -68,12 +71,13 @@ namespace SHADE
SHVec3 GetSimulationForce (void) const noexcept; SHVec3 GetSimulationForce (void) const noexcept;
uint32_t GetSimulationMaxSteps (void) const noexcept; uint32_t GetSimulationMaxSteps (void) const noexcept;
float GetSimulationTimestep (void) const noexcept; float GetSimulationTimestep (void) const noexcept;
float GetObjectMass (void) const noexcept;
void ResetSimulationInfo (void) noexcept; void ResetSimulationInfo (void) noexcept;
void OnCreate(void) override final; void OnCreate(void) override final;
void OnDestroy(void) override final; void OnDestroy(void) override final;
void SimulateTrajectory (EntityID eid, SHVec3 force, float timestep, uint32_t maxSteps) noexcept; void SimulateTrajectory (EntityID eid, float mass, SHVec3 force, float timestep, uint32_t maxSteps) noexcept;
RTTR_ENABLE() RTTR_ENABLE()

View File

@ -1,7 +1,6 @@
#include "SHpch.h" #include "SHpch.h"
#include "SHTrajectoryRenderingSubSystem.h" #include "SHTrajectoryRenderingSubSystem.h"
#include "../../../../SHGhostBody.h"
#include "ECS_Base/Managers/SHComponentManager.h" #include "ECS_Base/Managers/SHComponentManager.h"
#include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h" #include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h"
#include "Graphics/Devices/SHVkLogicalDevice.h" #include "Graphics/Devices/SHVkLogicalDevice.h"
@ -15,6 +14,7 @@
#include "Graphics/MiddleEnd/Interface/SHRenderer.h" #include "Graphics/MiddleEnd/Interface/SHRenderer.h"
#include "Physics/System/SHPhysicsSystem.h" #include "Physics/System/SHPhysicsSystem.h"
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include <Physics/System/SHGhostBody.h>
namespace SHADE namespace SHADE
{ {
@ -88,7 +88,13 @@ namespace SHADE
std::vector<SHVec3> positions{}; std::vector<SHVec3> positions{};
std::vector<SHQuaternion> quats{}; std::vector<SHQuaternion> quats{};
SHGhostBody defaultGhostBody{}; auto* rigidBodyComp = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityToSimulate);
if (!rigidBodyComp)
continue;
SHGhostBody defaultGhostBody{*rigidBodyComp};
defaultGhostBody.mass = comp.GetObjectMass();
SHPhysicsSystem::SimulateBodyInfo simulateInfo SHPhysicsSystem::SimulateBodyInfo simulateInfo
{ {
@ -109,6 +115,8 @@ namespace SHADE
comp.ResetSimulationInfo(); comp.ResetSimulationInfo();
std::cout << positions.size() << std::endl;
// If has positions, feed data to buffer. // If has positions, feed data to buffer.
if (!positions.empty()) if (!positions.empty())
{ {
@ -208,7 +216,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();

View File

@ -299,6 +299,8 @@ namespace SHADE
, created{ false } , created{ false }
{ {
if (pipelineLayout)
pipelineLayout->AddCallback([this]() {ConstructPipeline(); });
} }

View File

@ -372,6 +372,7 @@ namespace SHADE
, ISelfHandle<SHRenderGraphNode>{std::move(rhs)} , ISelfHandle<SHRenderGraphNode>{std::move(rhs)}
, dynamicIsActive {rhs.dynamicIsActive} , dynamicIsActive {rhs.dynamicIsActive}
, isDynamic {rhs.isDynamic} , isDynamic {rhs.isDynamic}
, preBeginFuncs{std::move(rhs.preBeginFuncs)}
{ {
rhs.renderpass = {}; rhs.renderpass = {};
@ -399,6 +400,7 @@ namespace SHADE
name = std::move(rhs.name); name = std::move(rhs.name);
dynamicIsActive = rhs.dynamicIsActive; dynamicIsActive = rhs.dynamicIsActive;
isDynamic = rhs.isDynamic; isDynamic = rhs.isDynamic;
preBeginFuncs = std::move(rhs.preBeginFuncs);
rhs.renderpass = {}; rhs.renderpass = {};
@ -493,6 +495,11 @@ namespace SHADE
return nodeCompute; return nodeCompute;
} }
void SHRenderGraphNode::AddPreBeginFunction(PreBeginFunction const& func) noexcept
{
preBeginFuncs.push_back(func);
}
/***************************************************************************/ /***************************************************************************/
/*! /*!
@ -664,6 +671,11 @@ namespace SHADE
void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept
{ {
for (auto& func : preBeginFuncs)
{
func(commandBuffer, frameIndex);
}
if (renderpass) if (renderpass)
{ {
uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0; uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0;

View File

@ -27,6 +27,10 @@ namespace SHADE
class SH_API SHRenderGraphNode : public ISelfHandle<SHRenderGraphNode> class SH_API SHRenderGraphNode : public ISelfHandle<SHRenderGraphNode>
{ {
public:
using PreBeginFunction = std::function<void(Handle<SHVkCommandBuffer>, uint32_t)>;
private: private:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER VARIABLES */ /* PRIVATE MEMBER VARIABLES */
@ -74,6 +78,9 @@ namespace SHADE
//! of drawing objects on the image (i.e. compute). //! of drawing objects on the image (i.e. compute).
std::vector<Handle<SHRenderGraphNodeCompute>> nodeComputes; std::vector<Handle<SHRenderGraphNodeCompute>> nodeComputes;
//! Calls before renderpass begins
std::vector<PreBeginFunction> preBeginFuncs;
//! Whether or not the node has finished execution //! Whether or not the node has finished execution
bool executed; bool executed;
@ -118,6 +125,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
Handle<SHSubpass> AddSubpass(std::string subpassName, Handle<SHViewport> viewport, Handle<SHRenderer> renderer) noexcept; Handle<SHSubpass> AddSubpass(std::string subpassName, Handle<SHViewport> viewport, Handle<SHRenderer> renderer) noexcept;
Handle<SHRenderGraphNodeCompute> AddNodeCompute(std::string nodeName, Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings = {}, uint32_t variableDescCount = 0, float numWorkGroupScale = 1.0f) noexcept; Handle<SHRenderGraphNodeCompute> AddNodeCompute(std::string nodeName, Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings = {}, uint32_t variableDescCount = 0, float numWorkGroupScale = 1.0f) noexcept;
void AddPreBeginFunction (PreBeginFunction const& func) noexcept;
void Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept; void Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
Handle<SHVkPipeline> GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept; Handle<SHVkPipeline> GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept;

View File

@ -94,8 +94,8 @@ namespace SHADE
Recompile(); Recompile();
//for (auto& callback : onChangeCallbacks) for (auto& callback : onChangeCallbacks)
// callback(); callback();
} }
void SHVkShaderModule::AddCallback(ChangeCallback&& callback) noexcept void SHVkShaderModule::AddCallback(ChangeCallback&& callback) noexcept

View File

@ -30,7 +30,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */ /* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
bool Wait (bool waitAll, uint64_t timer) noexcept; bool Wait (bool waitAll, uint64_t timer = std::numeric_limits<uint32_t>::max()) noexcept;
void Reset (void) noexcept; void Reset (void) noexcept;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/

View File

@ -38,13 +38,13 @@ namespace SHADE
localInvInertia.y = 1.0f / LOCAL_INERTIA.y; localInvInertia.y = 1.0f / LOCAL_INERTIA.y;
localInvInertia.z = 1.0f / LOCAL_INERTIA.z; localInvInertia.z = 1.0f / LOCAL_INERTIA.z;
linearLock.x = rigidBody.GetFreezePositionX() ? 1.0f : 0.0f; linearLock.x = rigidBody.GetFreezePositionX() ? 0.0f : 1.0f;
linearLock.y = rigidBody.GetFreezePositionY() ? 1.0f : 0.0f; linearLock.y = rigidBody.GetFreezePositionY() ? 0.0f : 1.0f;
linearLock.z = rigidBody.GetFreezePositionZ() ? 1.0f : 0.0f; linearLock.z = rigidBody.GetFreezePositionZ() ? 0.0f : 1.0f;
angularLock.x = rigidBody.GetFreezeRotationX() ? 1.0f : 0.0f; angularLock.x = rigidBody.GetFreezeRotationX() ? 0.0f : 1.0f;
angularLock.y = rigidBody.GetFreezeRotationY() ? 1.0f : 0.0f; angularLock.y = rigidBody.GetFreezeRotationY() ? 0.0f : 1.0f;
angularLock.z = rigidBody.GetFreezeRotationZ() ? 1.0f : 0.0f; angularLock.z = rigidBody.GetFreezeRotationZ() ? 0.0f : 1.0f;
} }

View File

@ -14,7 +14,6 @@
#include "SHPhysicsSystem.h" #include "SHPhysicsSystem.h"
// Project Headers // Project Headers
#include "../../../SHGhostBody.h"
#include "Assets/SHAssetMacros.h" #include "Assets/SHAssetMacros.h"
#include "ECS_Base/Managers/SHComponentManager.h" #include "ECS_Base/Managers/SHComponentManager.h"
#include "ECS_Base/Managers/SHEntityManager.h" #include "ECS_Base/Managers/SHEntityManager.h"
@ -25,6 +24,7 @@
#include "Physics/Interface/SHColliderComponent.h" #include "Physics/Interface/SHColliderComponent.h"
#include "Scene/SHSceneManager.h" #include "Scene/SHSceneManager.h"
#include "Scripting/SHScriptEngine.h" #include "Scripting/SHScriptEngine.h"
#include "SHGhostBody.h"
namespace SHADE namespace SHADE
{ {

View File

@ -248,6 +248,7 @@ namespace SHADE
AddComponentToComponentNode<SHUIComponent>(components, eid); AddComponentToComponentNode<SHUIComponent>(components, eid);
AddComponentToComponentNode<SHAudioListenerComponent>(components, eid); AddComponentToComponentNode<SHAudioListenerComponent>(components, eid);
AddComponentToComponentNode<SHTrajectoryRenderableComponent>(components, eid); AddComponentToComponentNode<SHTrajectoryRenderableComponent>(components, eid);
AddComponentToComponentNode<SHParticleEmitterComponent>(components, eid);
node[ComponentsNode] = components; node[ComponentsNode] = components;
@ -310,6 +311,7 @@ namespace SHADE
AddComponentID<SHUIComponent>(componentIDList, componentsNode); AddComponentID<SHUIComponent>(componentIDList, componentsNode);
AddComponentID<SHAudioListenerComponent>(componentIDList, componentsNode); AddComponentID<SHAudioListenerComponent>(componentIDList, componentsNode);
AddComponentID<SHTrajectoryRenderableComponent>(componentIDList, componentsNode); AddComponentID<SHTrajectoryRenderableComponent>(componentIDList, componentsNode);
AddComponentID<SHParticleEmitterComponent>(componentIDList, componentsNode);
return componentIDList; return componentIDList;
} }
@ -398,5 +400,6 @@ namespace SHADE
SHSerializationHelper::InitializeComponentFromNode<SHUIComponent>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHUIComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHAudioListenerComponent>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHAudioListenerComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHTrajectoryRenderableComponent>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHTrajectoryRenderableComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHParticleEmitterComponent>(componentsNode, eid);
} }
} }

View File

@ -17,6 +17,7 @@
#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" #include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h"
#include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h" #include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h"
#include "Physics/Collision/Shapes/SHCapsule.h" #include "Physics/Collision/Shapes/SHCapsule.h"
#include <Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h>
namespace YAML namespace YAML
{ {
@ -35,6 +36,9 @@ namespace YAML
struct HasYAMLConv<SHAnimatorComponent> : std::true_type {}; struct HasYAMLConv<SHAnimatorComponent> : std::true_type {};
template<> template<>
struct HasYAMLConv<SHTrajectoryRenderableComponent> : std::true_type {}; struct HasYAMLConv<SHTrajectoryRenderableComponent> : std::true_type {};
template<>
struct HasYAMLConv<SHParticleEmitterComponent> : std::true_type {};
template<> template<>
struct convert<SHVec4> struct convert<SHVec4>
@ -497,4 +501,120 @@ namespace YAML
} }
}; };
template<>
struct convert<SHParticleEmitterComponent>
{
static constexpr std::string_view EMISSION_COUNT_TAG = "Emission Count";
static constexpr std::string_view IS_PASSIVE_TAG = "Is Passive";
static constexpr std::string_view EMISSION_INTERVAL_TAG = "Emission Interval";
static constexpr std::string_view MIN_LIFE_TAG = "Min Life";
static constexpr std::string_view MAX_LIFE_TAG = "Max Life";
static constexpr std::string_view ANGULAR_RANGES_OFFSET_TAG = "Angular Ranges And Offset";
static constexpr std::string_view MIN_SIZE_TAG = "Minimum Size";
static constexpr std::string_view MAX_SIZE_TAG = "Maximum Size";
static constexpr std::string_view SIZE_DECAY_TAG = "Size Decay";
static constexpr std::string_view MIN_SPEED_TAG = "Minimum Speed";
static constexpr std::string_view MAX_SPEED_TAG = "Maximum Speed";
static constexpr std::string_view ROTATION_SPEED_TAG = "Rotation Speed";
static constexpr std::string_view ROTATION_DECAY_TAG = "Rotation Decay";
static constexpr std::string_view TEXTURE_ASSET_ID_TAG = "Texture Asset ID";
static constexpr std::string_view CUSTOM_UPDATE_SHADER_ASSET_ID_TAG = "Custom Update Shader Asset ID";
static YAML::Node encode(SHParticleEmitterComponent const& rhs)
{
YAML::Node node;
node[EMISSION_COUNT_TAG.data()] = rhs.GetEmissionCount();
node[IS_PASSIVE_TAG.data()] = rhs.GetPassive();
node[EMISSION_INTERVAL_TAG.data()] = rhs.GetEmissionInterval();
node[MIN_LIFE_TAG.data()] = rhs.GetMinLife();
node[MAX_LIFE_TAG.data()] = rhs.GetMaxLife();
node[MIN_SPEED_TAG.data()] = rhs.GetMinSpeed();
node[MAX_SPEED_TAG.data()] = rhs.GetMaxSpeed();
node[MIN_SIZE_TAG.data()] = rhs.GetMinSize();
node[MAX_SIZE_TAG.data()] = rhs.GetMaxSize();
node[SIZE_DECAY_TAG.data()] = rhs.GetSizeDecayMult();
node[ANGULAR_RANGES_OFFSET_TAG.data()] = rhs.GetAngularRangesAndOffsets();
node[ROTATION_SPEED_TAG.data()] = rhs.GetRotationSpeed();
node[ROTATION_DECAY_TAG.data()] = rhs.GetRotationDecay();
node[TEXTURE_ASSET_ID_TAG.data()] = rhs.GetTextureAssetID();
node[CUSTOM_UPDATE_SHADER_ASSET_ID_TAG.data()] = rhs.GetCustomUpdateShaderAssetID();
return node;
}
static bool decode(YAML::Node const& node, SHParticleEmitterComponent& rhs)
{
auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
if (node[EMISSION_COUNT_TAG.data()].IsDefined())
rhs.SetEmissionCount(node[EMISSION_COUNT_TAG.data()].as<uint32_t>());
if (node[IS_PASSIVE_TAG.data()].IsDefined())
rhs.SetPassive(node[IS_PASSIVE_TAG.data()].as<bool>());
if (node[EMISSION_INTERVAL_TAG.data()].IsDefined())
rhs.SetEmissionInterval(node[EMISSION_INTERVAL_TAG.data()].as<float>());
if (node[MIN_LIFE_TAG.data()].IsDefined())
rhs.SetMinLife(node[MIN_LIFE_TAG.data()].as<float>());
if (node[MAX_LIFE_TAG.data()].IsDefined())
rhs.SetMaxLife(node[MAX_LIFE_TAG.data()].as<float>());
if (node[SIZE_DECAY_TAG.data()].IsDefined())
rhs.SetSizeDecayMult(node[SIZE_DECAY_TAG.data()].as<float>());
if (node[ANGULAR_RANGES_OFFSET_TAG.data()].IsDefined())
rhs.SetAngularRangesAndOffsets(node[ANGULAR_RANGES_OFFSET_TAG.data()].as<SHVec4>());
if (node[MIN_SPEED_TAG.data()].IsDefined())
rhs.SetMinSpeed(node[MIN_SPEED_TAG.data()].as<float>());
if (node[MAX_SPEED_TAG.data()].IsDefined())
rhs.SetMaxSpeed (node[MAX_SPEED_TAG.data()].as<float>());
if (node[MAX_SIZE_TAG.data()].IsDefined())
rhs.SetMaxSize(node[MAX_SIZE_TAG.data()].as<float>());
if (node[ROTATION_SPEED_TAG.data()].IsDefined())
rhs.SetRotationSpeed(node[ROTATION_SPEED_TAG.data()].as<float>());
if (node[ROTATION_DECAY_TAG.data()].IsDefined())
rhs.SetRotationDecay(node[ROTATION_DECAY_TAG.data()].as<float>());
if (node[TEXTURE_ASSET_ID_TAG.data()].IsDefined())
{
AssetID id = node[TEXTURE_ASSET_ID_TAG.data()].as<AssetID>();
Handle<SHTexture> texture = SHResourceManager::LoadOrGet<SHTexture>(id);
SHResourceManager::FinaliseChanges();
//gfxSystem->BuildTextures();
if (texture)
{
rhs.SetTextureIndex(texture->TextureArrayIndex);
rhs.SetTextureAssetID(id);
}
else
{
SHLOG_WARNING ("Texture not set for particle emitter component: texture handle is null. ");
}
}
if (node[CUSTOM_UPDATE_SHADER_ASSET_ID_TAG.data()].IsDefined())
{
AssetID id = node[CUSTOM_UPDATE_SHADER_ASSET_ID_TAG.data()].as<AssetID>();
Handle<SHVkShaderModule> shaderModule = SHResourceManager::LoadOrGet<SHVkShaderModule>(id);
SHResourceManager::FinaliseChanges();
//gfxSystem->BuildTextures();
rhs.SetCustomUpdateShader(shaderModule);
rhs.SetTextureAssetID(id);
}
return true;
}
};
} }

View File

@ -13,9 +13,9 @@ namespace SHADE
} }
void TrajectoryRenderable::SimulateTrajectory(EntityID eid, Vector3 force, float timestep, uint32_t maxSteps) void TrajectoryRenderable::SimulateTrajectory(EntityID eid, float mass, Vector3 force, float timestep, uint32_t maxSteps)
{ {
GetNativeComponent()->SimulateTrajectory(eid, Convert::ToNative(force), timestep, maxSteps); GetNativeComponent()->SimulateTrajectory(eid, mass, Convert::ToNative(force), timestep, maxSteps);
} }
MeshAsset TrajectoryRenderable::Mesh::get() MeshAsset TrajectoryRenderable::Mesh::get()

View File

@ -83,7 +83,7 @@ namespace SHADE
void set(float val); void set(float val);
} }
void SimulateTrajectory(EntityID eid, Vector3 force, float timestep, uint32_t maxSteps); void SimulateTrajectory(EntityID eid, float mass, Vector3 force, float timestep, uint32_t maxSteps);
}; };
} }