#version 450 core #include "common.glsl" // Fully procedural rain: each instance is one streak in a box that follows // the camera target. Drops are fixed in world space (the box wraps around // them), fall at uWeather.z and slant with the wind. uniform vec3 uRainCenter; uniform vec2 uRainBox; // half extent (xz), height out vec2 vLocal; // x across the streak (-1..1), y along it (0 = head) out float vAlpha; void main() { int id = gl_InstanceID; vec3 h = vec3(hash12(vec2(float(id), 1.37)), hash12(vec2(float(id), 7.13)), hash12(vec2(float(id), 3.71))); float E = uRainBox.x, H = uRainBox.y; float speed = uWeather.z * (0.85 + 0.3 * h.x); vec2 wdir = normalize(uWind.xy + 1e-5); vec3 vel = vec3(wdir.x, 0.0, wdir.y) * uWind.z * 28.0 + vec3(0.0, -speed, 0.0); float age = fract(h.y + uTime * speed / H); // 0 = top of the box float tFall = age * H / speed; vec3 p; p.y = uRainCenter.y + H * 0.75 - age * H; vec2 base = h.xz * 2.0 * E + vel.xz * tFall; p.xz = uRainCenter.xz + mod(base - uRainCenter.xz + E, 2.0 * E) - E; vec3 dir = normalize(vel); float len = speed * 0.032; vec3 toCam = uCamPos.xyz - p; float dist = length(toCam); vec3 side = normalize(cross(dir, toCam / max(dist, 1e-3))); float width = 0.008 + dist * 0.0006; // never thinner than ~1 px vec2 corner = vec2(float(gl_VertexID & 1) * 2.0 - 1.0, float(gl_VertexID >> 1)); vec3 wp = p - dir * len * corner.y + side * width * corner.x; vLocal = corner; // Fade near the camera (big blurry drops) and at the box edges. vec2 rel = abs(p.xz - uRainCenter.xz) / E; vAlpha = smoothstep(1.5, 5.0, dist) * (1.0 - smoothstep(0.75, 1.0, max(rel.x, rel.y))) * (0.6 + 0.4 * h.z); gl_Position = uViewProj * vec4(wp, 1.0); }