17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-22 15:33:21 +02:00
Files
maszyna/shaders/particles_precipitation.comp

76 lines
3.8 KiB
Plaintext

// rain and snow of the gpu (opengl46_gpu_particles), in every colour pass which draws them: a thread per drop or flake. the
// particles fill three boxes around the camera, a small dense one and two larger ones, each repeated along the world axes:
// a particle keeps its place in the box, moved by how far the wind took them all and how far it fell, so nothing is kept
// from frame to frame. what the camera sees is lit (particle_light.glsl) and drawn as a streak from where it is to where
// it was a moment ago, seen from the moving camera (particles_precipitation.vert)
#include <common>
#include <weather_common.glsl>
#include <particle_light.glsl>
#include <particle_common.glsl>
layout(local_size_x = PARTICLE_GROUP_SIZE) in;
// x, y: first particles of the second and of the third box, z: particles, w: 1 for snow, 0 for rain
layout(location = 0) uniform uvec4 counts;
// xyz: how far the wind took the particles less where the camera is, in each box (metres, 0 to the size of the box); w: how
// far they fell in it, 0 to 16 sizes of the box
layout(location = 1) uniform vec4 offsets[3];
// xyz: size of each box, metres; w unused
layout(location = 4) uniform vec4 sizes;
// xyz: velocity of the wind less the one of the camera, m/s; w: speed of the fall
layout(location = 5) uniform vec4 velocity;
// x: seconds (for the flutter of the flakes), y: how long a streak lasts, seconds, z: opacity, w: places for the draws
layout(location = 6) uniform vec4 timing;
// the world axes around the camera to the view space of the pass
layout(location = 7) uniform mat4 view;
// y: how much a particle scatters the light onwards, z: brightness
layout(location = 11) uniform vec4 options;
layout(location = 12) uniform vec4 planes[5];
void main()
{
uint index = gl_GlobalInvocationID.x;
if (index >= counts.z)
return;
uint box = (index < counts.x) ? 0U : (index < counts.y) ? 1U : 2U;
float size = sizes[box];
bool snow = counts.w != 0U;
uint state = particle_hash(index * 3U + 0x9E3779B9U);
vec3 home = vec3(particle_random(state), particle_random(state), particle_random(state)) * size;
// the speed of the fall is (16 + k) / 16 of the common one, so a whole number of sizes of the box (16 of them) of the common
// fall is a whole number of them for every particle, and the fall can be kept within 16 sizes
float pace = (16.0 + floor(particle_random(state) * 7.0) - 3.0) / 16.0;
float width = snow ? mix(0.004, 0.012, particle_random(state)) : mix(0.0012, 0.0025, particle_random(state));
vec3 move = vec3(velocity.xyz) + vec3(0.0, -velocity.w * pace, 0.0);
vec3 place = home + offsets[box].xyz - vec3(0.0, offsets[box].w * pace, 0.0);
if (snow)
{
// the flakes flutter about their way
float amplitude = mix(0.1, 0.35, particle_random(state));
vec2 frequency = mix(vec2(1.5), vec2(5.0), vec2(particle_random(state), particle_random(state)));
vec2 phase = vec2(particle_random(state), particle_random(state)) * 6.2831853;
vec2 angle = frequency * timing.x + phase;
place.xz += amplitude * sin(angle);
move.xz += amplitude * frequency * cos(angle);
}
// within the box around the camera
vec3 world = mod(place, size) - 0.5 * size;
float opacity = timing.z;
// fading at the walls of the box, where the particles wrap around, and right at the camera
vec3 walls = abs(world) / (0.5 * size);
opacity *= 1.0 - smoothstep(0.7, 1.0, max(max(walls.x, walls.y), walls.z));
opacity *= smoothstep(0.15, 0.6, length(world));
if (opacity <= 0.002)
return;
vec3 tail = -move * timing.y;
float streak = length(tail);
if (streak > 3.0)
tail *= 3.0 / streak;
if (false == particle_visible(planes, world + 0.5 * tail, 0.5 * length(tail) + width))
return;
vec3 color = particle_light((view * vec4(world, 1.0)).xyz, world, options.y);
particle_emit(world, width, tail, color * options.z, opacity, uint(timing.w));
}