// storage of the particles of the gpu (gfx::gpu_particles, gl::particle_* in gl/ubo.h) for the compute passes; a kernel which // draws defines PARTICLE_COMMAND_BINDING and PARTICLE_OUTPUT_BINDING, the bindings of its pushed set the command and the draws // are at #ifndef PARTICLE_COMMON_GLSL #define PARTICLE_COMMON_GLSL // a particle of smoke; it's dead (or its place was never used) when its opacity is 0 or less struct smoke_particle_s { vec4 position; // xyz: metres from the origin of the particles (world axes), w: rotation, radians vec4 velocity; // xyz: m/s, w: size of the billboard, metres vec4 state; // x: opacity, y: age, seconds }; // a source of smoke as the last update of the simulation left it (smoke_source::gpu_state) struct smoke_source_s { uvec4 pool; // x: first place of the source in the storage, y: number of its places, z: place of the first particle born in the update, w: particles born vec4 location; // xyz: emitter at the update, from the origin vec4 previous; // xyz: emitter at the update before, from the origin vec4 launch; // xy: inclination, radians, zw: speed, m/s vec4 initial; // xy: size, zw: opacity vec4 sizechange; // x: per second, y: min, z: max, w: per metre the particle goes through the air (spread:) vec4 opacitychange; // x: per second, y: min, z: max vec4 motion; // x: rise, y: damping (per second, of the vertical velocity), z: least vertical velocity vec4 settling; // x: velocity the particles settle at, m/s upwards, y: drag, per second, z: 1 when they settle (in place of motion), w: seconds they take to show up (fade_in:) vec4 color; // rgb: colour of the smoke, lit by the lights of the pass vec4 oldcolor; // rgb: colour lit as the cpu does it, without the lights (gfx.smoke.lighting off) }; // what a draw of a particle reads, as attributes of an instance struct particle_draw_s { vec4 place; // xyz: metres from the camera (world axes), w: size (smoke) or width (rain, snow) vec4 shape; // x: rotation (smoke); xyz: from the head of the streak to its tail (rain, snow) vec4 color; // rgb: lit colour, a: opacity }; #ifdef PARTICLE_OUTPUT_BINDING // the indirect draw command of the particles; the compute passes count the instances layout(std430, set = COMPUTE_SET, binding = PARTICLE_COMMAND_BINDING) buffer particle_command_ssbo { uint particle_draw_vertices; uint particle_draw_instances; uint particle_draw_first; uint particle_draw_base; }; layout(std430, set = COMPUTE_SET, binding = PARTICLE_OUTPUT_BINDING) writeonly buffer particle_output_ssbo { particle_draw_s particle_draws[]; }; #endif // pcg hash uint particle_hash(uint value) { uint state = value * 747796405U + 2891336453U; uint word = ((state >> ((state >> 28U) + 4U)) ^ state) * 277803737U; return (word >> 22U) ^ word; } // next of a sequence of random numbers 0-1 float particle_random(inout uint state) { state = particle_hash(state); return float(state >> 8U) * (1.0 / 16777216.0); } // whether a sphere (centre from the camera along the world axes) is within the planes of the view bool particle_visible(vec4 planes[5], vec3 centre, float radius) { for (int i = 0; i < 5; i++) if (dot(planes[i].xyz, centre) + planes[i].w < -radius) return false; return true; } #ifdef PARTICLE_OUTPUT_BINDING // adds a particle to the draw; Capacity: the places of the storage of the draws void particle_emit(vec3 place, float size, vec3 shape, vec3 color, float opacity, uint capacity) { uint index = atomicAdd(particle_draw_instances, 1U); if (index >= capacity) { atomicAdd(particle_draw_instances, 0xFFFFFFFFU); return; } particle_draws[index].place = vec4(place, size); particle_draws[index].shape = vec4(shape, 0.0); particle_draws[index].color = vec4(color, opacity); } #endif #endif