#version 430 layout(points) in; layout(points) out; layout(max_vertices = 40) out; // All that we get from vertex shader in vec3 position_pass[]; in vec3 velocity_pass[]; in vec3 color_pass[]; in float lifetime_pass[]; in float size_pass[]; in float type_pass[]; // All that we send further out vec3 position_out; out vec3 velocity_out; out vec3 color_out; out float lifetime_out; out float size_out; out float type_out; uniform vec3 spawn_position; // Position where new particles are spawned uniform vec3 spawn_gravity; // Gravity vector for particles - updates velocity of particles uniform vec3 spawn_velocity_min; // Velocity of new particle - from min to (min+range) uniform vec3 spawn_velocity_range; uniform vec3 spawn_color; uniform float spawn_size; uniform float spawn_lifetime_min, spawn_lifetime_range; // Life of new particle - from min to (min+range) uniform float delta; // Time passed since last frame uniform vec3 random_seed; // Seed number for our random number function vec3 local_seed; uniform int number_to_generate; // How many particles will be generated next time, if greater than zero, particles are generated float random_zero_to_one() { uint n = floatBitsToUint(local_seed.y * 214013.0 + local_seed.x * 2531011.0 + local_seed.z * 141251.0); n = n * (n * n * 15731u + 789221u); n = (n >> 9u) | 0x3F800000u; float fRes = 2.0 - uintBitsToFloat(n); local_seed = vec3(local_seed.x + 147158.0 * fRes, local_seed.y*fRes + 415161.0 * fRes, local_seed.z + 324154.0*fRes); return fRes; } void main() { local_seed = random_seed; // gl_Position doesn't matter now, as rendering is discarded position_out = position_pass[0]; velocity_out = velocity_pass[0]; if(type_pass[0] != 0.0) position_out += velocity_out * delta; if(type_pass[0] != 0.0) velocity_out += spawn_gravity * delta; color_out = color_pass[0]; lifetime_out = lifetime_pass[0] - delta; size_out = size_pass[0]; type_out = type_pass[0]; if(type_out == 0.0) { // This is the emitter particle EmitVertex(); EndPrimitive(); for(int i = 0; i < number_to_generate; i++) { position_out = spawn_position; velocity_out = spawn_velocity_min + vec3( spawn_velocity_range.x * random_zero_to_one(), spawn_velocity_range.y * random_zero_to_one(), spawn_velocity_range.z * random_zero_to_one() ); color_out = spawn_color; lifetime_out = spawn_lifetime_min + spawn_lifetime_range * random_zero_to_one(); size_out = spawn_size; type_out = 1.0; EmitVertex(); EndPrimitive(); } } else if (lifetime_out > 0.0) { // This is a normal particle which is still alive EmitVertex(); EndPrimitive(); } else if (type_out == 1.0) { // The lifetime is over -- transform this particle in a new one or discard for(int i = 0; i < 5; i++) { // Keep the position velocity_out = spawn_velocity_min + vec3( spawn_velocity_range.x * random_zero_to_one(), spawn_velocity_range.y * random_zero_to_one(), spawn_velocity_range.z * random_zero_to_one() ); color_out = vec3(1.0, 0, 0); lifetime_out = spawn_lifetime_min + spawn_lifetime_range * random_zero_to_one(); size_out = spawn_size; type_out = 2.0; EmitVertex(); EndPrimitive(); } } else if (type_out == 2.0) { // The lifetime is over -- transform this particle in a new one or discard for(int i = 0; i < 5; i++) { // Keep the position velocity_out = spawn_velocity_min + vec3( spawn_velocity_range.x * random_zero_to_one(), spawn_velocity_range.y * random_zero_to_one(), spawn_velocity_range.z * random_zero_to_one() ); color_out = vec3(0.0, 1.0, 0); lifetime_out = spawn_lifetime_min + spawn_lifetime_range * random_zero_to_one(); size_out = spawn_size; type_out = 3.0; EmitVertex(); EndPrimitive(); } } }