quakeforge/libs/video/renderer/vulkan/shader/partupdate.comp
Bill Currie 8228146ac0 [vulkan] Use the particle system buffer for indirect draws
I realized I'd need to get the particle counts out to the draw commands
somehow, and this seemed to be the most natural way.
2021-12-24 06:45:13 +09:00

105 lines
2.5 KiB
Text

#version 450
layout (constant_id = 0) const int MaxParticles = 2048;
layout (local_size_x = 1, local_size_y = 1) in;
struct Particle {
vec4 pos;
vec4 vel;
vec4 color;
float tex;
float ramp;
float scale;
float live;
};
struct Parameters {
vec4 drag; // [dx, dy, dz, grav scale]
vec4 ramp; // [rate, max, alpha rate, scale rate]
};
layout(std140, set = 0, binding = 0) buffer InStates {
Particle particles[];
} inState;
layout(std140, set = 0, binding = 1) buffer InParameters {
Parameters parameters[];
} inParameters;
//doubles as VkDrawIndirectCommand
layout(std140, set = 0, binding = 2) buffer InSystem {
uint vertexCount;
uint particleCount; //instanceCount
uint firstVertex;
uint firstInstance;
} inSystem;
layout(std140, set = 1, binding = 0) buffer OutStates {
Particle particles[];
} outStates;
layout(std140, set = 1, binding = 1) buffer OutParameters {
Parameters parameters[];
} outParameters;
//doubles as VkDrawIndirectCommand
layout(std140, set = 1, binding = 2) buffer OutSystem {
uint vertexCount;
uint particleCount; //instanceCount
uint firstVertex;
uint firstInstance;
} outSystem;
layout(std140, set = 2, binding = 0) buffer NewStates {
Particle particles[];
} newStates;
layout(std140, set = 2, binding = 1) buffer NewParameters {
Parameters parameters[];
} newParameters;
//doubles as VkDrawIndirectCommand
layout(std140, set = 2, binding = 2) buffer NewSystem {
uint vertexCount;
uint particleCount; //instanceCount
uint firstVertex;
uint firstInstance;
} newSystem;
bool
is_dead (in Particle part, in Parameters parm)
{
if (part.live <= 0) {
return true;
}
if (part.ramp >= parm.ramp.y || part.color.a <= 0 || part.scale <= 0) {
return true;
}
return false;
}
void
main ()
{
uint j = 0;
// compact existing partles removing dead particles
for (uint i = 0; i < inSystem.particleCount; i++) {
if (is_dead (inState.particles[i], inParameters.parameters[i])) {
continue;
}
outStates.particles[j] = inState.particles[i];
outParameters.parameters[j] = inParameters.parameters[i];
j++;
}
// inject any new particles that aren't DOA
for (uint i = 0; i < newSystem.particleCount && j < MaxParticles; i++) {
if (is_dead (inState.particles[i], inParameters.parameters[i])) {
continue;
}
outStates.particles[j] = newStates.particles[i];
outParameters.parameters[j] = newParameters.parameters[i];
j++;
}
outSystem.particleCount = j;
}