diff options
Diffstat (limited to 'servers/rendering/rasterizer_rd/shaders/particles.glsl')
-rw-r--r-- | servers/rendering/rasterizer_rd/shaders/particles.glsl | 238 |
1 files changed, 185 insertions, 53 deletions
diff --git a/servers/rendering/rasterizer_rd/shaders/particles.glsl b/servers/rendering/rasterizer_rd/shaders/particles.glsl index 7cdedfcbfe..a924509771 100644 --- a/servers/rendering/rasterizer_rd/shaders/particles.glsl +++ b/servers/rendering/rasterizer_rd/shaders/particles.glsl @@ -66,6 +66,38 @@ layout(set = 1, binding = 1, std430) restrict buffer Particles { } particles; +#define EMISSION_FLAG_HAS_POSITION 1 +#define EMISSION_FLAG_HAS_ROTATION_SCALE 2 +#define EMISSION_FLAG_HAS_VELOCITY 4 +#define EMISSION_FLAG_HAS_COLOR 8 +#define EMISSION_FLAG_HAS_CUSTOM 16 + +struct ParticleEmission { + mat4 xform; + vec3 velocity; + uint flags; + vec4 color; + vec4 custom; +}; + +layout(set = 1, binding = 2, std430) restrict volatile coherent buffer SourceEmission { + int particle_count; + uint pad0; + uint pad1; + uint pad2; + ParticleEmission data[]; +} +src_particles; + +layout(set = 1, binding = 3, std430) restrict volatile coherent buffer DestEmission { + int particle_count; + int particle_max; + uint pad1; + uint pad2; + ParticleEmission data[]; +} +dst_particles; + /* SET 2: MATERIAL */ #ifdef USE_MATERIAL_UNIFORMS @@ -82,7 +114,9 @@ layout(push_constant, binding = 0, std430) uniform Params { uint total_particles; uint trail_size; bool use_fractional_delta; - uint pad[3]; + bool sub_emitter_mode; + bool can_emit; + uint pad; } params; @@ -93,6 +127,51 @@ uint hash(uint x) { return x; } +bool emit_particle(mat4 p_xform, vec3 p_velocity, vec4 p_color, vec4 p_custom, uint p_flags) { + if (!params.can_emit) { + return false; + } + + bool valid = false; + + int dst_index = atomicAdd(dst_particles.particle_count, 1); + + if (dst_index >= dst_particles.particle_max) { + atomicAdd(dst_particles.particle_count, -1); + return false; + } + /* + valid = true; + + int attempts = 256; // never trust compute + while(attempts-- > 0) { + dst_index = dst_particles.particle_count; + if (dst_index == dst_particles.particle_max) { + return false; //can't emit anymore + } + + if (atomicCompSwap(dst_particles.particle_count, dst_index, dst_index +1 ) != dst_index) { + continue; + } + valid=true; + break; + } + + barrier(); + + if (!valid) { + return false; //gave up (attempts exhausted) + } +*/ + dst_particles.data[dst_index].xform = p_xform; + dst_particles.data[dst_index].velocity = p_velocity; + dst_particles.data[dst_index].color = p_color; + dst_particles.data[dst_index].custom = p_custom; + dst_particles.data[dst_index].flags = p_flags; + + return true; +} + /* clang-format off */ COMPUTE_SHADER_GLOBALS @@ -118,76 +197,129 @@ void main() { float mass = 1.0; - float restart_phase = float(index) / float(params.total_particles); + bool restart = false; - if (FRAME.randomness > 0.0) { - uint seed = FRAME.cycle; - if (restart_phase >= FRAME.system_phase) { - seed -= uint(1); - } - seed *= uint(params.total_particles); - seed += uint(index); - float random = float(hash(seed) % uint(65536)) / 65536.0; - restart_phase += FRAME.randomness * random * 1.0 / float(params.total_particles); + bool restart_position = false; + bool restart_rotation_scale = false; + bool restart_velocity = false; + bool restart_color = false; + bool restart_custom = false; + + if (params.clear) { + PARTICLE.color = vec4(1.0); + PARTICLE.custom = vec4(0.0); + PARTICLE.velocity = vec3(0.0); + PARTICLE.is_active = false; + PARTICLE.xform = mat4( + vec4(1.0, 0.0, 0.0, 0.0), + vec4(0.0, 1.0, 0.0, 0.0), + vec4(0.0, 0.0, 1.0, 0.0), + vec4(0.0, 0.0, 0.0, 1.0)); } - restart_phase *= (1.0 - FRAME.explosiveness); + if (params.sub_emitter_mode) { + if (!PARTICLE.is_active) { + int src_index = atomicAdd(src_particles.particle_count, -1) - 1; - bool restart = false; + if (src_index >= 0) { + PARTICLE.is_active = true; + restart = true; - if (FRAME.system_phase > FRAME.prev_system_phase) { - // restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed + if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_POSITION)) { + PARTICLE.xform[3] = src_particles.data[src_index].xform[3]; + } else { + PARTICLE.xform[3] = vec4(0, 0, 0, 1); + restart_position = true; + } + if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_ROTATION_SCALE)) { + PARTICLE.xform[0] = src_particles.data[src_index].xform[0]; + PARTICLE.xform[1] = src_particles.data[src_index].xform[1]; + PARTICLE.xform[2] = src_particles.data[src_index].xform[2]; + } else { + PARTICLE.xform[0] = vec4(1, 0, 0, 0); + PARTICLE.xform[1] = vec4(0, 1, 0, 0); + PARTICLE.xform[2] = vec4(0, 0, 1, 0); + restart_rotation_scale = true; + } + if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_VELOCITY)) { + PARTICLE.velocity = src_particles.data[src_index].velocity; + } else { + PARTICLE.velocity = vec3(0); + restart_velocity = true; + } + if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_COLOR)) { + PARTICLE.color = src_particles.data[src_index].color; + } else { + PARTICLE.color = vec4(1); + restart_color = true; + } - if (restart_phase >= FRAME.prev_system_phase && restart_phase < FRAME.system_phase) { - restart = true; - if (params.use_fractional_delta) { - local_delta = (FRAME.system_phase - restart_phase) * params.lifetime; + if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_CUSTOM)) { + PARTICLE.custom = src_particles.data[src_index].custom; + } else { + PARTICLE.custom = vec4(0); + restart_custom = true; + } } } - } else if (FRAME.delta > 0.0) { - if (restart_phase >= FRAME.prev_system_phase) { - restart = true; - if (params.use_fractional_delta) { - local_delta = (1.0 - restart_phase + FRAME.system_phase) * params.lifetime; - } + } else if (FRAME.emitting) { + float restart_phase = float(index) / float(params.total_particles); - } else if (restart_phase < FRAME.system_phase) { - restart = true; - if (params.use_fractional_delta) { - local_delta = (FRAME.system_phase - restart_phase) * params.lifetime; + if (FRAME.randomness > 0.0) { + uint seed = FRAME.cycle; + if (restart_phase >= FRAME.system_phase) { + seed -= uint(1); } + seed *= uint(params.total_particles); + seed += uint(index); + float random = float(hash(seed) % uint(65536)) / 65536.0; + restart_phase += FRAME.randomness * random * 1.0 / float(params.total_particles); } - } - uint current_cycle = FRAME.cycle; + restart_phase *= (1.0 - FRAME.explosiveness); - if (FRAME.system_phase < restart_phase) { - current_cycle -= uint(1); - } + if (FRAME.system_phase > FRAME.prev_system_phase) { + // restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed - uint particle_number = current_cycle * uint(params.total_particles) + particle; + if (restart_phase >= FRAME.prev_system_phase && restart_phase < FRAME.system_phase) { + restart = true; + if (params.use_fractional_delta) { + local_delta = (FRAME.system_phase - restart_phase) * params.lifetime; + } + } - if (restart) { - PARTICLE.is_active = FRAME.emitting; - } + } else if (FRAME.delta > 0.0) { + if (restart_phase >= FRAME.prev_system_phase) { + restart = true; + if (params.use_fractional_delta) { + local_delta = (1.0 - restart_phase + FRAME.system_phase) * params.lifetime; + } -#ifdef ENABLE_KEEP_DATA - if (params.clear) { -#else - if (params.clear || restart) { -#endif - PARTICLE.color = vec4(1.0); - PARTICLE.custom = vec4(0.0); - PARTICLE.velocity = vec3(0.0); - if (!restart) { - PARTICLE.is_active = false; + } else if (restart_phase < FRAME.system_phase) { + restart = true; + if (params.use_fractional_delta) { + local_delta = (FRAME.system_phase - restart_phase) * params.lifetime; + } + } + } + + uint current_cycle = FRAME.cycle; + + if (FRAME.system_phase < restart_phase) { + current_cycle -= uint(1); + } + + uint particle_number = current_cycle * uint(params.total_particles) + particle; + + if (restart) { + PARTICLE.is_active = FRAME.emitting; + restart_position = true; + restart_rotation_scale = true; + restart_velocity = true; + restart_color = true; + restart_custom = true; } - PARTICLE.xform = mat4( - vec4(1.0, 0.0, 0.0, 0.0), - vec4(0.0, 1.0, 0.0, 0.0), - vec4(0.0, 0.0, 1.0, 0.0), - vec4(0.0, 0.0, 0.0, 1.0)); } if (PARTICLE.is_active) { |