Improved particles and trajectory rendering #430
|
@ -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: ~
|
|
@ -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);
|
||||||
|
|
Binary file not shown.
|
@ -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;
|
||||||
}
|
}
|
Binary file not shown.
|
@ -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.
|
@ -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); });
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
@ -116,10 +115,9 @@ namespace SHADE
|
||||||
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;
|
||||||
|
|
||||||
|
@ -129,10 +127,9 @@ namespace SHADE
|
||||||
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;
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>());
|
||||||
|
|
Loading…
Reference in New Issue