Improved particles and trajectory rendering #430

Merged
Xenosas1337 merged 19 commits from SP3-1-Rendering into main 2023-03-20 16:55:29 +08:00
13 changed files with 145 additions and 180 deletions
Showing only changes of commit 32ef4d8c55 - Show all commits

View File

@ -158,15 +158,14 @@
IsActive: true IsActive: true
classSHADE::SHParticleEmitterComponent: classSHADE::SHParticleEmitterComponent:
Emission Count: 1 Emission Count: 1
Is Passive: false Is Passive: true
Emission Interval: 3 Emission Interval: 0.200000003
Min Life: 7 Min Life: 2
Max Life: 20 Max Life: 3
Angular Min: {x: 2.29999995, y: 1.70000005, z: 2.9000001} Minimum Speed: 3
Angular Max: {x: 0, y: 0, z: 0} Maximum Speed: 6
Minimum Velocity: {x: 1, y: 1, z: 0} Minimum Size: 0
Maximum Velocity: {x: 2, y: 2, z: 0} Maximum Size: 0.5
Minimum Size: 1 Angular Ranges And Offset: {x: 0, y: 0, z: 0, w: 0}
Maximum Size: 3
IsActive: true IsActive: true
Scripts: ~ Scripts: ~

View File

@ -4,10 +4,10 @@ layout(local_size_x = 128) in;
struct EmitterParameters struct EmitterParameters
{ {
vec4 angularMin; vec4 angularRangesAndOffsets;
vec4 angularMax; float minSpeed;
vec4 minVel; float maxSpeed;
vec4 maxVel; float padding[2];
vec4 lifeAndSizeRange; // min life, max life, min size, max size vec4 lifeAndSizeRange; // min life, max life, min size, max size
}; };
@ -107,6 +107,9 @@ void main()
{ {
uint emitterInvocationIndex = gl_GlobalInvocationID.x; uint emitterInvocationIndex = gl_GlobalInvocationID.x;
vec4 emitterPosition = emitterPushConstant.emitterPosition; 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;
@ -127,15 +130,24 @@ void main()
// emit particle from emitter position // emit particle from emitter position
particle.position = vec4 (emitterPosition.xyz, 1.0f); 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 // Set its velocity
particle.velocity = emitterParams.data.minVel; particle.velocity.xyz = vec3 (cos(eulerAngles.x) * cos(eulerAngles.y),
sin(eulerAngles.x) * cos(eulerAngles.y),
sin(eulerAngles.y));
particle.velocity *= map (rand (seed), 0.0f, 1.0f, minSpeed.x, maxSpeed.x);
// randomize life value that ranges from minLife to maxLife // 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); 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 // Set size of particle
particle.scaleAndDecay.x = emitterParams.data.lifeAndSizeRange.z; particle.scaleAndDecay.x = particleSize;
particle.scaleAndDecay.z = emitterParams.data.lifeAndSizeRange.z; particle.scaleAndDecay.z = particleSize;
particle.rotation = vec4 (5.0f); particle.rotation = vec4 (5.0f);
particle.acceleration = vec4 (0.01f); particle.acceleration = vec4 (0.01f);

View File

@ -119,23 +119,23 @@ void main()
if (particle.life > 0.0f) if (particle.life > 0.0f)
{ {
// update position from velocity // update position from velocity
// particle.position += particle.velocity * genericDataBuffer.data.dt; particle.position += particle.velocity * genericDataBuffer.data.dt;
// particle.life -= genericDataBuffer.data.dt; particle.life -= genericDataBuffer.data.dt;
if (particle.life < 0.0f || particle.scaleAndDecay.x < 0.0f || particle.scaleAndDecay.y < 0.0f) if (particle.life < 0.0f || particle.scaleAndDecay.x < 0.0f || particle.scaleAndDecay.y < 0.0f)
{ {
particle.life = 0.0f; particle.life = 0.0f;
particle.position.x = 99999.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;
// indirectArgs.instanceCount = 1;
} }
outputParticles.data[index] = particle;
} }

View File

@ -74,24 +74,22 @@ void main()
ParticleData particle = outputParticles.data[indices[gl_InstanceIndex]]; ParticleData particle = outputParticles.data[indices[gl_InstanceIndex]];
vec3 normalized = normalize (particle.velocity.xyz); vec3 normalized = normalize (particle.velocity.xyz);
float angle = atan (normalized.y, normalized.x); float angle = 1.1f;
// float angle = atan (normalized.y, normalized.x);
vec2 particleScaleData = particle.scaleAndDecay.xz; // x and y vec2 particleScaleData = particle.scaleAndDecay.xz; // x and y
mat4 localModel = mat4 (1.0f); mat3 rotate = mat3 (1.0f);
localModel[0][0] = 1.0f;
localModel[1][1] = 1.0f;
// localModel[0][0] = particleScaleData.x;
// localModel[1][1] = particleScaleData.y;
mat4 rotate = mat4(1.0f);
rotate[0][0] = cos(angle); rotate[0][0] = cos(angle);
rotate[0][1] = sin(angle); rotate[0][1] = sin(angle);
rotate[1][0] = -sin(angle); rotate[1][0] = -sin(angle);
rotate[1][1] = cos(angle); rotate[1][1] = cos(angle);
// localModel = rotate * localModel;
localModel[3] = vec4 (particle.position.xyz, 1.0f); vec3 particlePos = rotate * vertexPos;
// gl_Position = cameraData.vpMat * localModel * vec4(vertexPos, 1.0f);
gl_Position = vec4(vertexPos, 1.0f); 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);
gl_Position = cameraData.vpMat * vec4(particlePos, 1.0f);
} }

Binary file not shown.

View File

@ -827,46 +827,37 @@ namespace SHADE
SHEditorWidgets::DragFloat("Min Life", [comp = component]() {return comp->GetMinLife(); }, [comp = component](float val) {comp->SetMinLife(val); }); 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("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("Min Size", [comp = component]() {return comp->GetMinSize(); }, [comp = component](float val) {comp->SetMinSize(val); });
SHEditorWidgets::DragFloat("Man Size", [comp = component]() {return comp->GetMaxSize(); }, [comp = component](float val) {comp->SetMaxSize(val); }); SHEditorWidgets::DragFloat("Max Size", [comp = component]() {return comp->GetMaxSize(); }, [comp = component](float val) {comp->SetMaxSize(val); });
SHEditorWidgets::DragVec3("Angular Min", {"x", "y", "z"}, SHEditorWidgets::DragVec4("Angles and Offsets", {"yaw", "pitch", "yaw off", "pitch off"},
[comp = component]() [comp = component]()
{ {
return comp->GetAngularMin(); return comp->GetAngularRangesAndOffsets();
}, },
[comp = component](SHVec3 const& val) [comp = component](SHVec4 const& val)
{ {
comp->SetAngularMin(val); comp->SetAngularRangesAndOffsets(val);
}); });
SHEditorWidgets::DragVec3("Angular Max", { "x", "y", "z" },
SHEditorWidgets::DragFloat("Min Speed",
[comp = component]() [comp = component]()
{ {
return comp->GetAngularMax(); return comp->GetMinSpeed();
}, },
[comp = component](SHVec3 const& val) [comp = component](float val)
{ {
comp->SetAngularMax(val); comp->SetMinSpeed(val);
}); });
SHEditorWidgets::DragVec3("Min Vel", { "x", "y", "z" }, SHEditorWidgets::DragFloat("Max Speed",
[comp = component]() [comp = component]()
{ {
return comp->GetMinVelocity(); return comp->GetMaxSpeed();
}, },
[comp = component](SHVec3 const& val) [comp = component](float val)
{ {
comp->SetMinVelocity(val); comp->SetMaxSpeed(val);
});
SHEditorWidgets::DragVec3("Max Vel", { "x", "y", "z" },
[comp = component]()
{
return comp->GetMaxVelocity();
},
[comp = component](SHVec3 const& val)
{
comp->SetMaxVelocity(val);
}); });
SHEditorWidgets::CheckBox("Is Passive", [comp = component]() {return comp->GetPassive(); }, [comp = component](bool flag) {comp->SetPassive(flag); }); SHEditorWidgets::CheckBox("Is Passive", [comp = component]() {return comp->GetPassive(); }, [comp = component](bool flag) {comp->SetPassive(flag); });

View File

@ -46,24 +46,20 @@ namespace SHADE
cpuEmitterData.lifeAndSizeRange.y = val; cpuEmitterData.lifeAndSizeRange.y = val;
} }
void SHParticleEmitterComponent::SetAngularMin(SHVec3 const& min) noexcept void SHParticleEmitterComponent::SetAngularRangesAndOffsets(SHVec4 const& ranges) noexcept
{ {
cpuEmitterData.angularMin = SHVec4 (min); cpuEmitterData.angularRangesAndOffsets = SHVec4 (ranges);
} }
void SHParticleEmitterComponent::SetAngularMax(SHVec3 const& max) noexcept
void SHParticleEmitterComponent::SetMinSpeed(float speed) noexcept
{ {
cpuEmitterData.angularMax = SHVec4(max); cpuEmitterData.minSpeed = speed;
} }
void SHParticleEmitterComponent::SetMinVelocity(SHVec3 const& vel) noexcept void SHParticleEmitterComponent::SetMaxSpeed(float speed) noexcept
{ {
cpuEmitterData.minVel = vel; cpuEmitterData.maxSpeed = speed;
}
void SHParticleEmitterComponent::SetMaxVelocity(SHVec3 const& vel) noexcept
{
cpuEmitterData.maxVel = vel;
} }
void SHParticleEmitterComponent::SetMinSize(float size) noexcept void SHParticleEmitterComponent::SetMinSize(float size) noexcept
@ -102,19 +98,19 @@ namespace SHADE
} }
SHVec3 SHParticleEmitterComponent::GetAngularMin(void) const noexcept SHVec4 const& SHParticleEmitterComponent::GetAngularRangesAndOffsets(void) const noexcept
{ {
return SHVec3 (cpuEmitterData.angularMin.x, cpuEmitterData.angularMin.y, cpuEmitterData.angularMin.z); return cpuEmitterData.angularRangesAndOffsets;
} }
SHVec3 SHParticleEmitterComponent::GetMinVelocity(void) const noexcept float SHParticleEmitterComponent::GetMinSpeed(void) const noexcept
{ {
return SHVec3(cpuEmitterData.minVel.x, cpuEmitterData.minVel.y, cpuEmitterData.minVel.z); return cpuEmitterData.minSpeed;
} }
SHVec3 SHParticleEmitterComponent::GetMaxVelocity(void) const noexcept float SHParticleEmitterComponent::GetMaxSpeed(void) const noexcept
{ {
return SHVec3(cpuEmitterData.maxVel.x, cpuEmitterData.maxVel.y, cpuEmitterData.maxVel.z); return cpuEmitterData.maxSpeed;
} }
float SHParticleEmitterComponent::GetMinSize(void) const noexcept float SHParticleEmitterComponent::GetMinSize(void) const noexcept
@ -127,9 +123,5 @@ namespace SHADE
return cpuEmitterData.lifeAndSizeRange.w; return cpuEmitterData.lifeAndSizeRange.w;
} }
SHVec3 SHParticleEmitterComponent::GetAngularMax(void) const noexcept
{
return SHVec3(cpuEmitterData.angularMax.x, cpuEmitterData.angularMax.y, cpuEmitterData.angularMax.z);
}
} }

View File

@ -16,17 +16,16 @@ namespace SHADE
private: private:
struct GPUEmitterStruct struct GPUEmitterStruct
{ {
//! Minimum emitting angular range //! Angular ranges of emission
SHVec4 angularMin; SHVec4 angularRangesAndOffsets;
//! Maximum emitting angular range
SHVec4 angularMax;
//! minimum starting velocity //! minimum starting velocity
SHVec4 minVel; float minSpeed;
//! Maximum starting velocity //! Maximum starting velocity
SHVec4 maxVel; float maxSpeed;
float padding[2];
//! Spawn lifetime and size range (min and max) //! Spawn lifetime and size range (min and max)
SHVec4 lifeAndSizeRange; SHVec4 lifeAndSizeRange;
@ -111,30 +110,28 @@ namespace SHADE
void Emit (void) noexcept; void Emit (void) noexcept;
void SetEmissionCount (uint32_t count) noexcept; void SetEmissionCount (uint32_t count) noexcept;
void SetPassive (bool flag) noexcept; void SetPassive (bool flag) noexcept;
void SetEmissionInterval (float interval) noexcept; void SetEmissionInterval (float interval) noexcept;
void SetMinLife (float val) noexcept; void SetMinLife (float val) noexcept;
void SetMaxLife (float val) noexcept; void SetMaxLife (float val) noexcept;
void SetAngularMin (SHVec3 const& min) noexcept; void SetAngularRangesAndOffsets (SHVec4 const& ranges) noexcept;
void SetAngularMax (SHVec3 const& max) noexcept; void SetMinSpeed (float speed) noexcept;
void SetMinVelocity (SHVec3 const& vel) noexcept; void SetMaxSpeed (float speed) noexcept;
void SetMaxVelocity (SHVec3 const& vel) noexcept; void SetMinSize (float size) noexcept;
void SetMinSize (float size) noexcept; void SetMaxSize (float size) noexcept;
void SetMaxSize (float size) noexcept;
uint32_t GetEmissionCount (void) const noexcept; uint32_t GetEmissionCount (void) const noexcept;
bool GetPassive (void) const noexcept; bool GetPassive (void) const noexcept;
float GetEmissionInterval (void) const noexcept; float GetEmissionInterval (void) const noexcept;
float GetMinLife (void) const noexcept; float GetMinLife (void) const noexcept;
float GetMaxLife (void) const noexcept; float GetMaxLife (void) const noexcept;
SHVec3 GetAngularMax (void) const noexcept; SHVec4 const& GetAngularRangesAndOffsets (void) const noexcept;
SHVec3 GetAngularMin (void) const noexcept; float GetMinSpeed (void) const noexcept;
SHVec3 GetMinVelocity (void) const noexcept; float GetMaxSpeed (void) const noexcept;
SHVec3 GetMaxVelocity (void) const noexcept; float GetMinSize (void) const noexcept;
float GetMinSize (void) const noexcept; float GetMaxSize (void) const noexcept;
float GetMaxSize (void) const noexcept;
friend class SHParticleSubSystem; friend class SHParticleSubSystem;

View File

@ -23,7 +23,7 @@ namespace SHADE
void SHParticleSubSystem::InitializeComponent(SHParticleEmitterComponent& comp) noexcept void SHParticleSubSystem::InitializeComponent(SHParticleEmitterComponent& comp) noexcept
{ {
// TODO: temporary only. // TODO: temporary only.
static constexpr uint32_t NUM_PARTICLES = 5; 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 sizeofUint = static_cast<uint32_t>(sizeof(uint32_t));
@ -166,34 +166,46 @@ namespace SHADE
//cmdBuffer->DrawArrays(4, 1, 0, 0); //cmdBuffer->DrawArrays(4, 1, 0, 0);
} }
void SHParticleSubSystem::PreparePrePostUpdateBarriers(std::vector<vk::BufferMemoryBarrier>& preUpdateBarriers, std::vector<vk::BufferMemoryBarrier>& postUpdateBarriers, std::vector<vk::BufferMemoryBarrier>& preDrawBarriers, SHParticleEmitterComponent const& emitter, uint32_t const EMITTER_INDEX, uint32_t const FRAME_INDEX) noexcept 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. // pre-update particles data barrier. Note that this is for input because we want the input to be available before we use it.
vk::BufferMemoryBarrier particleDataBarrier vk::BufferMemoryBarrier inputParticleDataBarrierPreUpdate
{ {
.srcAccessMask = vk::AccessFlagBits::eShaderWrite, .srcAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite,
.dstAccessMask = vk::AccessFlagBits::eShaderRead, .dstAccessMask = vk::AccessFlagBits::eShaderRead,
.buffer = emitter.particleData->GetVkBuffer(), .buffer = emitter.particleData->GetVkBuffer(),
.offset = emitter.dynamicOffsets[FRAME_INDEX][DYOFF_INDEX_PARTICLE_INPUT], .offset = emitter.dynamicOffsets[FRAME_INDEX][DYOFF_INDEX_PARTICLE_INPUT],
.size = emitter.chunkSize .size = emitter.chunkSize
}; };
// pre-update free list data barrier // pre-update free list data barrier.
vk::BufferMemoryBarrier freelistDataBarrier vk::BufferMemoryBarrier freelistDataBarrierPreUpdate
{ {
.srcAccessMask = vk::AccessFlagBits::eShaderWrite, .srcAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite,
.dstAccessMask = vk::AccessFlagBits::eShaderRead, .dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite,
.buffer = emitter.freelistData->GetVkBuffer(), .buffer = emitter.freelistData->GetVkBuffer(),
.offset = 0, // Only 1 copy of freelist data, so offset is at 0 .offset = 0, // Only 1 copy of freelist data, so offset is at 0
.size = static_cast<uint32_t>(sizeof (uint32_t)) * (emitter.maxParticles + 1) .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 // ...copy assign barriers on heap
preUpdateBarriers[EMITTER_INDEX * 2] = particleDataBarrier; preUpdateBarriers[EMITTER_INDEX * 3] = inputParticleDataBarrierPreUpdate;
preUpdateBarriers[(EMITTER_INDEX * 2) + 1] = freelistDataBarrier; preUpdateBarriers[(EMITTER_INDEX * 3) + 1] = freelistDataBarrierPreUpdate;
preUpdateBarriers[(EMITTER_INDEX * 3) + 2] = indicesDataBarrierPreUpdate;
// make new barrier on stack... // make new barrier on stack...
vk::BufferMemoryBarrier particleDataBarrierPost vk::BufferMemoryBarrier outputParticleDataBarrierPostUpdate
{ {
.srcAccessMask = vk::AccessFlagBits::eShaderWrite, .srcAccessMask = vk::AccessFlagBits::eShaderWrite,
.dstAccessMask = vk::AccessFlagBits::eShaderRead, .dstAccessMask = vk::AccessFlagBits::eShaderRead,
@ -203,7 +215,7 @@ namespace SHADE
}; };
// make new barrier on stack... // make new barrier on stack...
vk::BufferMemoryBarrier indicesDataBarrier vk::BufferMemoryBarrier indicesDataBarrierPostUpdate
{ {
.srcAccessMask = vk::AccessFlagBits::eShaderWrite, .srcAccessMask = vk::AccessFlagBits::eShaderWrite,
.dstAccessMask = vk::AccessFlagBits::eShaderRead, .dstAccessMask = vk::AccessFlagBits::eShaderRead,
@ -213,9 +225,9 @@ namespace SHADE
}; };
// make new barrier on stack... // make new barrier on stack...
vk::BufferMemoryBarrier drawDataBarrier vk::BufferMemoryBarrier drawDataBarrierPostUpdate
{ {
.srcAccessMask = vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eMemoryWrite, .srcAccessMask = vk::AccessFlagBits::eShaderWrite,
.dstAccessMask = vk::AccessFlagBits::eIndirectCommandRead, .dstAccessMask = vk::AccessFlagBits::eIndirectCommandRead,
.buffer = emitter.drawCallData->GetVkBuffer(), .buffer = emitter.drawCallData->GetVkBuffer(),
.offset = emitter.dynamicOffsets[FRAME_INDEX][DYOFF_INDEX_DRAW_DATA], .offset = emitter.dynamicOffsets[FRAME_INDEX][DYOFF_INDEX_DRAW_DATA],
@ -223,9 +235,9 @@ namespace SHADE
}; };
// ...copy assign barriers on heap // ...copy assign barriers on heap
postUpdateBarriers[EMITTER_INDEX * 2] = particleDataBarrierPost; postUpdateBarriers[EMITTER_INDEX * 3] = outputParticleDataBarrierPostUpdate;
postUpdateBarriers[(EMITTER_INDEX * 2) + 1] = indicesDataBarrier; postUpdateBarriers[(EMITTER_INDEX * 3) + 1] = indicesDataBarrierPostUpdate;
preDrawBarriers[EMITTER_INDEX] = drawDataBarrier; postUpdateBarriers[(EMITTER_INDEX * 3) + 2] = drawDataBarrierPostUpdate;
} }
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
@ -322,12 +334,12 @@ namespace SHADE
// Every emitter will have its own barrier for its particle data and freelist data. Indices data is not needed since // 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. // 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() * 2); preUpdateBarriers.resize(emitters.size() * 3);
// After we invoke the updates for the emitters, we need to make sure all particles and indices data are done updating // 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. // before we issue them for rendering.
std::vector<vk::BufferMemoryBarrier> postUpdateBarriers{}; std::vector<vk::BufferMemoryBarrier> postUpdateBarriers{};
postUpdateBarriers.resize(emitters.size() * 2); postUpdateBarriers.resize(emitters.size() * 3);
std::vector<vk::BufferMemoryBarrier> preDrawBarriers{}; std::vector<vk::BufferMemoryBarrier> preDrawBarriers{};
preDrawBarriers.resize(emitters.size()); preDrawBarriers.resize(emitters.size());
@ -340,8 +352,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);
@ -385,7 +395,7 @@ namespace SHADE
} }
// prepare barriers // prepare barriers
PreparePrePostUpdateBarriers(preUpdateBarriers, postUpdateBarriers, preDrawBarriers, emitter, i, frameIndex); PreparePrePostUpdateBarriers(preUpdateBarriers, postUpdateBarriers, emitter, i, frameIndex);
// Emitter will emit once and stop emitting next frame (unless specified before reaching here to do so). // Emitter will emit once and stop emitting next frame (unless specified before reaching here to do so).
emitter.toEmit = false; emitter.toEmit = false;
@ -393,7 +403,7 @@ namespace SHADE
} }
// issue the barrier to wait // issue the barrier to wait
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {}, preUpdateBarriers, {}); cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eDrawIndirect, vk::PipelineStageFlagBits::eComputeShader, {}, {}, preUpdateBarriers, {});
@ -414,39 +424,13 @@ namespace SHADE
/* AFTER UPDATING, RENDER PARTICLES */ /* AFTER UPDATING, RENDER PARTICLES */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
// issue the barrier to wait for output particles to be done updating and indices data to finish being modified. // issue the barrier to wait for output particles to be done updating and indices data to finish being modified.
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {}, postUpdateBarriers, {}); cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eDrawIndirect | vk::PipelineStageFlagBits::eVertexShader, {}, {}, postUpdateBarriers, {});
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eDrawIndirect, {}, {}, preDrawBarriers, {});
} }
void SHParticleSubSystem::ResetInstanceCounts(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept void SHParticleSubSystem::ResetInstanceCounts(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
{ {
auto& emitters = SHComponentManager::GetDense<SHParticleEmitterComponent>(); auto& emitters = SHComponentManager::GetDense<SHParticleEmitterComponent>();
std::vector<vk::BufferMemoryBarrier> preResetBarriers{};
preResetBarriers.resize(emitters.size());
uint32_t i = 0;
for (auto& emitter : emitters)
{
if (emitter.initialized)
{
// pre-update particles data barrier. Note that this is for input because we want the input to be available before we use it.
vk::BufferMemoryBarrier drawDataHostWriteBarrier
{
.srcAccessMask = vk::AccessFlagBits::eIndirectCommandRead | vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite,
.dstAccessMask = vk::AccessFlagBits::eMemoryWrite | vk::AccessFlagBits::eHostWrite,
.buffer = emitter.drawCallData->GetVkBuffer(),
.offset = emitter.dynamicOffsets[frameIndex][DYOFF_INDEX_DRAW_DATA],
.size = static_cast<uint32_t>(sizeof(vk::DrawIndirectCommand))
};
preResetBarriers[i] = drawDataHostWriteBarrier;
}
++i;
}
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eDrawIndirect, vk::PipelineStageFlagBits::eHost, {}, {}, preResetBarriers, {});
for (auto& emitter : emitters) for (auto& emitter : emitters)
{ {

View File

@ -73,7 +73,7 @@ namespace SHADE
//! Pipeline data for updating particles //! Pipeline data for updating particles
PipelineData defaultUpdatePipelineData; PipelineData defaultUpdatePipelineData;
//! Desc pool for particle component desc set allocation //! Desc pool for particle component desc set allocation
Handle<SHVkDescriptorPool> descPool; Handle<SHVkDescriptorPool> descPool;
@ -82,7 +82,7 @@ namespace SHADE
void UpdateCompoennt(Handle<SHVkCommandBuffer> cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept; void UpdateCompoennt(Handle<SHVkCommandBuffer> cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept;
void RenderComponent(Handle<SHVkCommandBuffer> cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept; void RenderComponent(Handle<SHVkCommandBuffer> cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept;
void PreparePrePostUpdateBarriers (std::vector<vk::BufferMemoryBarrier>& preUpdateBarriers, std::vector<vk::BufferMemoryBarrier>& postUpdateBarriers, std::vector<vk::BufferMemoryBarrier>& preDrawBarriers, SHParticleEmitterComponent const& emitter, uint32_t const EMITTER_INDEX, uint32_t const FRAME_INDEX) noexcept; void PreparePrePostUpdateBarriers (std::vector<vk::BufferMemoryBarrier>& preUpdateBarriers, std::vector<vk::BufferMemoryBarrier>& postUpdateBarriers, SHParticleEmitterComponent const& emitter, uint32_t const EMITTER_INDEX, uint32_t const FRAME_INDEX) noexcept;
public: public:
void Init(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> inDescPool, Handle<SHVkRenderpass> compatibleRenderpass, Handle<SHSubpass> subpass, Handle<SHVkShaderModule> VS, Handle<SHVkShaderModule> FS, Handle<SHVkShaderModule> emitCS, Handle<SHVkShaderModule> defaultUpdateCS) noexcept; void Init(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> inDescPool, Handle<SHVkRenderpass> compatibleRenderpass, Handle<SHSubpass> subpass, Handle<SHVkShaderModule> VS, Handle<SHVkShaderModule> FS, Handle<SHVkShaderModule> emitCS, Handle<SHVkShaderModule> defaultUpdateCS) noexcept;

View File

@ -509,12 +509,11 @@ namespace YAML
static constexpr std::string_view EMISSION_INTERVAL_TAG = "Emission Interval"; 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 MIN_LIFE_TAG = "Min Life";
static constexpr std::string_view MAX_LIFE_TAG = "Max Life"; static constexpr std::string_view MAX_LIFE_TAG = "Max Life";
static constexpr std::string_view ANGULAR_MIN_TAG = "Angular Min"; static constexpr std::string_view ANGULAR_RANGES_OFFSET_TAG = "Angular Ranges And Offset";
static constexpr std::string_view ANGULAR_MAX_TAG = "Angular Max";
static constexpr std::string_view MIN_VEL_TAG = "Minimum Velocity";
static constexpr std::string_view MAX_VEL_TAG = "Maximum Velocity";
static constexpr std::string_view MIN_SIZE_TAG = "Minimum Size"; 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 MAX_SIZE_TAG = "Maximum Size";
static constexpr std::string_view MIN_SPEED_TAG = "Minimum Speed";
static constexpr std::string_view MAX_SPEED_TAG = "Maximum Speed";
static YAML::Node encode(SHParticleEmitterComponent const& rhs) static YAML::Node encode(SHParticleEmitterComponent const& rhs)
{ {
@ -524,12 +523,11 @@ namespace YAML
node[EMISSION_INTERVAL_TAG.data()] = rhs.GetEmissionInterval(); node[EMISSION_INTERVAL_TAG.data()] = rhs.GetEmissionInterval();
node[MIN_LIFE_TAG.data()] = rhs.GetMinLife(); node[MIN_LIFE_TAG.data()] = rhs.GetMinLife();
node[MAX_LIFE_TAG.data()] = rhs.GetMaxLife(); node[MAX_LIFE_TAG.data()] = rhs.GetMaxLife();
node[ANGULAR_MIN_TAG.data()] = rhs.GetAngularMin(); node[MIN_SPEED_TAG.data()] = rhs.GetMinSpeed();
node[ANGULAR_MAX_TAG.data()] = rhs.GetAngularMax(); node[MAX_SPEED_TAG.data()] = rhs.GetMaxSpeed();
node[MIN_VEL_TAG.data()] = rhs.GetMinVelocity();
node[MAX_VEL_TAG.data()] = rhs.GetMaxVelocity();
node[MIN_SIZE_TAG.data()] = rhs.GetMinSize(); node[MIN_SIZE_TAG.data()] = rhs.GetMinSize();
node[MAX_SIZE_TAG.data()] = rhs.GetMaxSize(); node[MAX_SIZE_TAG.data()] = rhs.GetMaxSize();
node[ANGULAR_RANGES_OFFSET_TAG.data()] = rhs.GetAngularRangesAndOffsets();
return node; return node;
} }
@ -550,20 +548,14 @@ namespace YAML
if (node[MAX_LIFE_TAG.data()].IsDefined()) if (node[MAX_LIFE_TAG.data()].IsDefined())
rhs.SetMaxLife(node[MAX_LIFE_TAG.data()].as<float>()); rhs.SetMaxLife(node[MAX_LIFE_TAG.data()].as<float>());
if (node[ANGULAR_MIN_TAG.data()].IsDefined()) if (node[ANGULAR_RANGES_OFFSET_TAG.data()].IsDefined())
rhs.SetAngularMin(node[ANGULAR_MIN_TAG.data()].as<SHVec3>()); rhs.SetAngularRangesAndOffsets(node[ANGULAR_RANGES_OFFSET_TAG.data()].as<SHVec4>());
if (node[ANGULAR_MAX_TAG.data()].IsDefined()) if (node[MIN_SPEED_TAG.data()].IsDefined())
rhs.SetAngularMax(node[ANGULAR_MAX_TAG.data()].as<SHVec3>()); rhs.SetMinSpeed(node[MIN_SPEED_TAG.data()].as<float>());
if (node[MIN_VEL_TAG.data()].IsDefined()) if (node[MAX_SPEED_TAG.data()].IsDefined())
rhs.SetMinVelocity(node[MIN_VEL_TAG.data()].as<SHVec3>()); rhs.SetMaxSpeed (node[MAX_SPEED_TAG.data()].as<float>());
if (node[MAX_VEL_TAG.data()].IsDefined())
rhs.SetMaxVelocity(node[MAX_VEL_TAG.data()].as<SHVec3>());
if (node[MIN_SIZE_TAG.data()].IsDefined())
rhs.SetMinSize(node[MIN_SIZE_TAG.data()].as<float>());
if (node[MAX_SIZE_TAG.data()].IsDefined()) if (node[MAX_SIZE_TAG.data()].IsDefined())
rhs.SetMaxSize(node[MAX_SIZE_TAG.data()].as<float>()); rhs.SetMaxSize(node[MAX_SIZE_TAG.data()].as<float>());