GLSL Basic Snow Shader
I made this shader because I've wanted to create some animations for the holiday season for a long while, but I just couldn't grok shaders..
AI is a phenomenal tool for learning though, and it helped me a lot here.
The problem with shaders is that they're extremely hard to debug.
You have to basically track every single function's input and output range, and you also have to know what kind of curve they describe.
This becomes pretty difficult when you're beginning to combine multiple functions together.
Anyways, here's the shader with some settings:
hide controls
Controls
Code
The vertex shader is just a big triangle that contains the entire screen from -1 to +1, so we can draw to the entire canvas (screen) in the fragment shader.
I've been lazy and I just redefined some variables to make the fragment shader work in WebGL. The original shader was made in Shadertoy, which uses slightly different variable names.
Here's the fragment shader:
1precision highp float;
2
3uniform float u_time;
4uniform vec2 u_resolution;
5
6uniform float u_speed_min;
7uniform float u_speed_max;
8uniform float u_radius_min;
9uniform float u_radius_max;
10
11
12float hash(float n)
13{
14 return fract(sin(n) * 43758.5453123);
15}
16
17vec2 hash2(float n)
18{
19 return vec2(hash(n), hash(n + 17.0));
20}
21
22
23void main()
24{
25 // translate shadertoy vars to built in opengl es ones
26 vec2 iResolution = u_resolution;
27 float iTime = u_time;
28 vec4 fragColor;
29 vec2 fragCoord = gl_FragCoord.xy;
30 // -------------------------------------
31
32 vec2 uv = fragCoord / iResolution.xy;
33 uv.x *= iResolution.x / iResolution.y; // aspect correction
34
35 float t = iTime;
36
37 float col = 0.0;
38
39 const int COUNT = 70;
40
41 // loop over every possible snowflake
42 // render it if pixel is inside one
43 for (int i = 0; i < COUNT; i++)
44 {
45 float fi = float(i);
46
47 // random base position
48 vec2 r = hash2(fi);
49
50 // x position, corrected for screen aspect
51 float x = r.x * (iResolution.x / iResolution.y);
52
53 // y position, falling over time
54 float speed = mix(u_speed_min, u_speed_max, r.y);
55 float y = 1.0 - fract(t * speed + r.y);
56
57 vec2 pos = vec2(x, y);
58
59 // random circle size
60 float radius = mix(u_radius_min, u_radius_max, hash(fi + 42.0));
61
62 // circle sdf, blurred edges
63 float d = length(uv - pos);
64 float blur = mix(0.05, 0.1, radius);
65 float circle = smoothstep(radius, radius - blur, d);
66
67 col += circle;
68 }
69
70 col = clamp(col, 0.0, 1.0);
71
72 fragColor = vec4(vec3(col), 1.0);
73
74 // convert back to opengl es compatible vars
75 gl_FragColor = fragColor;
76}