summaryrefslogtreecommitdiff
path: root/themes/src/_shaders
diff options
context:
space:
mode:
Diffstat (limited to 'themes/src/_shaders')
-rw-r--r--themes/src/_shaders/grass.frag11
-rw-r--r--themes/src/_shaders/grass.vert25
-rw-r--r--themes/src/_shaders/sky.frag78
-rw-r--r--themes/src/_shaders/sky.vert10
-rw-r--r--themes/src/_shaders/snowflake.frag73
-rw-r--r--themes/src/_shaders/snowflake.vert30
-rw-r--r--themes/src/_shaders/sun.frag40
-rw-r--r--themes/src/_shaders/sun.vert27
-rw-r--r--themes/src/_shaders/water.frag63
-rw-r--r--themes/src/_shaders/water.vert63
10 files changed, 410 insertions, 10 deletions
diff --git a/themes/src/_shaders/grass.frag b/themes/src/_shaders/grass.frag
new file mode 100644
index 0000000..a72f078
--- /dev/null
+++ b/themes/src/_shaders/grass.frag
@@ -0,0 +1,11 @@
+varying lowp vec2 vUV;
+
+void main() {
+ lowp float halfWidth = 0.5 * (1.0 - vUV.y);
+ lowp float distFromCenter = abs(vUV.x - 0.5);
+ if (distFromCenter > halfWidth) discard;
+
+ lowp vec3 baseColor = vec3(0.15, 0.45, 0.10);
+ lowp vec3 tipColor = vec3(0.40, 0.75, 0.20);
+ gl_FragColor = vec4(mix(baseColor, tipColor, vUV.y), 1.0);
+}
diff --git a/themes/src/_shaders/grass.vert b/themes/src/_shaders/grass.vert
new file mode 100644
index 0000000..0cf0285
--- /dev/null
+++ b/themes/src/_shaders/grass.vert
@@ -0,0 +1,25 @@
+attribute vec2 position; // Local quad vertex: x in [-0.5, 0.5], y in [0, 1]
+attribute vec3 instancePos; // Per-instance: world-space base of blade
+attribute float instancePhase; // Per-instance: random phase offset for sway
+attribute float instanceHeight; // Per-instance: height scale multiplier
+
+uniform mat4 projection;
+uniform mat4 view;
+uniform float time;
+uniform float bladeWidth;
+uniform float bladeHeight;
+uniform float swayAmount;
+
+varying lowp vec2 vUV;
+
+void main() {
+ vec3 cameraRight = vec3(view[0][0], view[1][0], view[2][0]);
+ float h = bladeHeight * instanceHeight;
+ float sway = sin(time * 1.5 + instancePhase) * swayAmount * position.y;
+ vec3 worldPos = instancePos
+ + cameraRight * (position.x + sway) * bladeWidth
+ + vec3(0.0, 1.0, 0.0) * position.y * h;
+
+ gl_Position = projection * view * vec4(worldPos, 1.0);
+ vUV = vec2(position.x + 0.5, position.y);
+}
diff --git a/themes/src/_shaders/sky.frag b/themes/src/_shaders/sky.frag
new file mode 100644
index 0000000..a2eb18b
--- /dev/null
+++ b/themes/src/_shaders/sky.frag
@@ -0,0 +1,78 @@
+precision highp float;
+
+varying vec2 vUv;
+
+uniform float time; // seconds, for slow cloud drift
+uniform float horizon; // screen-space y of the water horizon (~0.5)
+
+float hash(vec2 p) {
+ p = fract(p * vec2(123.34, 456.21));
+ p += dot(p, p + 45.32);
+ return fract(p.x * p.y);
+}
+
+float valueNoise(vec2 p) {
+ vec2 i = floor(p);
+ vec2 f = fract(p);
+ float a = hash(i);
+ float b = hash(i + vec2(1.0, 0.0));
+ float c = hash(i + vec2(0.0, 1.0));
+ float d = hash(i + vec2(1.0, 1.0));
+ vec2 u = f * f * (3.0 - 2.0 * f);
+ return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
+}
+
+float fbm(vec2 p) {
+ float v = 0.0;
+ float amp = 0.5;
+ for (int i = 0; i < 4; i++) {
+ v += amp * valueNoise(p);
+ p *= 2.0;
+ amp *= 0.5;
+ }
+ return v;
+}
+
+const vec3 SKY_HORIZON = vec3(0.80, 0.88, 0.98); // matches water horizon fade
+const vec3 SKY_TOP = vec3(0.22, 0.48, 0.86); // deeper zenith blue
+const vec3 CLOUD_COLOR = vec3(1.00, 0.98, 0.95); // white, slightly warm
+
+const float DEPTH_BIAS = 0.05; // caps frequency at the horizon (larger = gentler shrink)
+const float CLOUD_FREQ = 2.7; // overall cloud scale (larger = more, smaller clouds)
+const float X_STRETCH = 0.35; // < 1 stretches clouds horizontally -> wispy
+const float CLOUD_THRESH = 0.55; // coverage cutoff; higher = sparser sky
+const float CLOUD_SOFT = 0.22; // edge softness of the cloud mask
+const float CLOUD_OPACITY = 0.85; // max cloud whiteness
+const float DRIFT_SPEED = 0.03; // slow lateral drift (noise units / sec)
+const float H_FADE = 0.12; // band over which clouds fade in above horizon
+
+void main() {
+ // Height above the water horizon: 0 at the waterline, (1 - horizon) at the top.
+ float above = max(vUv.y - horizon, 0.0);
+
+ // Vertical gradient.
+ float g = clamp(above / (1.0 - horizon), 0.0, 1.0);
+ vec3 col = mix(SKY_HORIZON, SKY_TOP, pow(g, 0.75));
+ float haze = 1.0 - smoothstep(0.0, 0.35, g);
+ col += vec3(0.06, 0.04, 0.00) * haze;
+
+ // Flat cloud-ceiling perspective: distance along the view ~ 1/above, so
+ // features shrink AND compress vertically toward the horizon.
+ float depth = 1.0 / (above + DEPTH_BIAS);
+ vec2 q;
+ q.x = (vUv.x - 0.5) * depth;
+ q.y = depth;
+
+ vec2 p = vec2(q.x * X_STRETCH, q.y) * CLOUD_FREQ;
+ p.x += time * DRIFT_SPEED;
+
+ float n = fbm(p);
+ float cloud = smoothstep(CLOUD_THRESH, CLOUD_THRESH + CLOUD_SOFT, n);
+
+ // Fade clouds into the haze right at the horizon.
+ cloud *= smoothstep(0.0, H_FADE, above);
+
+ col = mix(col, CLOUD_COLOR, cloud * CLOUD_OPACITY);
+
+ gl_FragColor = vec4(col, 1.0);
+}
diff --git a/themes/src/_shaders/sky.vert b/themes/src/_shaders/sky.vert
new file mode 100644
index 0000000..249603c
--- /dev/null
+++ b/themes/src/_shaders/sky.vert
@@ -0,0 +1,10 @@
+precision highp float;
+
+attribute vec2 position; // fullscreen quad, clip-space corners in [-1, 1]
+
+varying vec2 vUv;
+
+void main() {
+ vUv = position * 0.5 + 0.5; // uv.y = 0 bottom, 1 top
+ gl_Position = vec4(position, 0.0, 1.0);
+}
diff --git a/themes/src/_shaders/snowflake.frag b/themes/src/_shaders/snowflake.frag
new file mode 100644
index 0000000..d887cf5
--- /dev/null
+++ b/themes/src/_shaders/snowflake.frag
@@ -0,0 +1,73 @@
+// Procedural star fragment shader
+varying lowp vec2 vUV;
+varying lowp float vSeed;
+varying lowp float vScale;
+
+const lowp float PI = 3.14159265359;
+
+// Simple hash function for deterministic randomness
+lowp float hash(lowp float n) {
+ return fract(sin(n) * 43758.5453123);
+}
+
+// Generate star pattern procedurally
+lowp float starPattern(lowp vec2 uv) {
+ lowp float dist = length(uv);
+ lowp float angle = atan(uv.y, uv.x);
+
+ // Number of star points (4 or 5)
+ lowp float numPoints = 4.0 + floor(hash(vSeed) * 2.0);
+
+ // Create sharp star with triangular points
+ lowp float angleStep = 2.0 * PI / numPoints;
+ lowp float currentAngle = mod(angle + PI / numPoints, angleStep) - angleStep * 0.5;
+
+ // Create triangular points - distance from center to edge varies linearly with angle
+ lowp float normalizedAngle = abs(currentAngle) / (angleStep * 0.5);
+
+ // Outer tip radius and inner valley radius
+ lowp float tipRadius = 0.5;
+ lowp float valleyRadius = 0.15;
+
+ // Linear interpolation creates sharp triangular points
+ lowp float rayEdge = mix(tipRadius, valleyRadius, normalizedAngle);
+
+ // Hard cutoff for sharp edges
+ lowp float star = step(dist, rayEdge);
+
+ return star;
+}
+
+void main() {
+ lowp float pattern = starPattern(vUV);
+
+ // Color variation based on seed - white and blue tints
+ lowp float colorVar = hash(vSeed * 3.0);
+ lowp vec3 starColor;
+
+ if (colorVar < 0.5) {
+ // Pure white
+ starColor = vec3(1.0, 1.0, 1.0);
+ } else if (colorVar < 0.75) {
+ // Light blue tint
+ starColor = vec3(0.9, 0.95, 1.0);
+ } else {
+ // Stronger blue tint
+ starColor = vec3(0.85, 0.92, 1.0);
+ }
+
+ // Scale alpha based on size - smaller stars are more transparent
+ // Normalize scale from range [16, 48] to [0, 1]
+ lowp float sizeRatio = (vScale - 16.0) / (48.0 - 16.0);
+ // Map to alpha range [0.3, 1.0] - smaller stars at 30% opacity, larger at 100%
+ lowp float alpha = mix(0.3, 1.0, sizeRatio);
+
+ lowp vec4 color = vec4(starColor, pattern * alpha);
+
+ // Discard fully transparent pixels for performance
+ if (color.a < 0.01) {
+ discard;
+ }
+
+ gl_FragColor = color;
+}
diff --git a/themes/src/_shaders/snowflake.vert b/themes/src/_shaders/snowflake.vert
new file mode 100644
index 0000000..7cbfb99
--- /dev/null
+++ b/themes/src/_shaders/snowflake.vert
@@ -0,0 +1,30 @@
+// Instanced snowflake vertex shader
+attribute vec2 position; // Base quad vertex position
+attribute vec2 instancePos; // Per-instance: snowflake center position
+attribute float instanceRot; // Per-instance: rotation angle
+attribute float instanceScale; // Per-instance: size scale
+attribute float instanceSeed; // Per-instance: random seed for variation
+
+uniform mat4 projection;
+uniform mat4 model;
+
+varying lowp vec2 vUV; // UV coordinates for fragment shader
+varying lowp float vSeed; // Pass seed to fragment shader
+varying lowp float vScale; // Pass scale to fragment shader
+
+void main() {
+ // Rotate and scale the base quad
+ float c = cos(instanceRot);
+ float s = sin(instanceRot);
+ mat2 rotation = mat2(c, s, -s, c);
+
+ vec2 rotatedPos = rotation * (position * instanceScale);
+ vec2 worldPos = instancePos + rotatedPos;
+
+ gl_Position = projection * model * vec4(worldPos, 0.0, 1.0);
+
+ // Pass UV in range [-1, 1] for procedural generation
+ vUV = position;
+ vSeed = instanceSeed;
+ vScale = instanceScale;
+}
diff --git a/themes/src/_shaders/sun.frag b/themes/src/_shaders/sun.frag
index 8463e06..2170b39 100644
--- a/themes/src/_shaders/sun.frag
+++ b/themes/src/_shaders/sun.frag
@@ -1,5 +1,43 @@
varying lowp vec4 VertexColor;
+varying lowp vec2 TexCoord;
+uniform lowp float time;
+
+// Simple noise function for edge distortion
+lowp float noise(lowp vec2 p) {
+ return sin(p.x * 10.0 + time) * cos(p.y * 10.0 + time * 0.5) * 0.5 + 0.5;
+}
void main() {
- gl_FragColor = VertexColor;
+ // TexCoord is now normalized: center is (0,0), edges are at distance ~1
+ lowp float dist = length(TexCoord);
+
+ // Add animated noise to the edge
+ lowp float angle = atan(TexCoord.y, TexCoord.x);
+ lowp float wave = sin(angle * 8.0 + time * 2.0) * 0.05 + sin(angle * 4.0 - time * 1.5) * 0.03;
+ lowp float noiseValue = noise(TexCoord + time * 0.1) * 0.02;
+
+ // Create soft edge using smoothstep - ensure fade reaches zero at the actual edge
+ lowp float innerEdge = 0.8;
+ lowp float outerEdge = 1.0;
+ lowp float alpha = 1.0 - smoothstep(innerEdge, outerEdge, dist);
+
+ // Apply wave distortion to the edge
+ alpha *= 1.0 - smoothstep(0.85 + wave + noiseValue * 2.0, 1.0, dist);
+
+ // Make edges more transparent but not too much
+ alpha = alpha * alpha;
+
+ // Add slight glow effect at the edge
+ lowp float glow = smoothstep(0.5, 0.8, dist) * (1.0 - smoothstep(0.8, 1.0, dist));
+
+ // Create orange gradient from center
+ lowp vec3 orangeColor = vec3(1.0, 0.5, 0.1);
+ lowp float centerGradient = smoothstep(0.6, 0.0, dist);
+ lowp vec3 baseColor = mix(VertexColor.rgb, orangeColor, centerGradient * 0.6);
+
+ // Mix in the glow with a brighter color
+ lowp vec3 glowColor = baseColor * 1.3;
+ lowp vec3 finalColor = mix(baseColor, glowColor, glow * 0.5);
+
+ gl_FragColor = vec4(finalColor, VertexColor.a * alpha);
}
diff --git a/themes/src/_shaders/sun.vert b/themes/src/_shaders/sun.vert
index 76150f0..5ed77d7 100644
--- a/themes/src/_shaders/sun.vert
+++ b/themes/src/_shaders/sun.vert
@@ -1,13 +1,22 @@
-attribute vec2 position;
-attribute vec4 color;
-attribute mat4 vMatrix;
-uniform mat4 projection;
-uniform mat4 model;
+attribute vec2 position;
+attribute vec4 color;
+attribute mat4 vMatrix;
+uniform mat4 projection;
+uniform mat4 model;
varying lowp vec4 VertexColor;
+varying lowp vec2 TexCoord;
-void main() {
- vec4 fragmentPosition = projection * model * vMatrix * vec4(position.x, position.y, 0, 1);
- gl_Position = fragmentPosition;
- VertexColor = color;
+void main() {
+ vec4 fragmentPosition = projection * model * vMatrix * vec4(position.x, position.y, 0, 1);
+ gl_Position = fragmentPosition;
+ VertexColor = color;
+ // Normalize the position - the center is at (0,0) and edge vertices are at distance 'radius'
+ // We want TexCoord to be in the range roughly [-1, 1] at the edges
+ lowp float maxDist = length(position);
+ if (maxDist > 0.1) {
+ TexCoord = position / maxDist;
+ } else {
+ TexCoord = vec2(0.0, 0.0);
+ }
}
diff --git a/themes/src/_shaders/water.frag b/themes/src/_shaders/water.frag
new file mode 100644
index 0000000..0ceffeb
--- /dev/null
+++ b/themes/src/_shaders/water.frag
@@ -0,0 +1,63 @@
+precision highp float;
+
+varying vec3 vWorldPos;
+varying vec3 vNormal;
+
+uniform vec3 cameraPos;
+uniform vec3 sunDir; // normalized direction from the water toward the sun
+uniform vec3 sunColor;
+uniform float time;
+
+float hash(vec2 p) {
+ p = fract(p * vec2(123.34, 456.21));
+ p += dot(p, p + 45.32);
+ return fract(p.x * p.y);
+}
+
+float valueNoise(vec2 p) {
+ vec2 i = floor(p);
+ vec2 f = fract(p);
+ float a = hash(i);
+ float b = hash(i + vec2(1.0, 0.0));
+ float c = hash(i + vec2(0.0, 1.0));
+ float d = hash(i + vec2(1.0, 1.0));
+ vec2 u = f * f * (3.0 - 2.0 * f);
+ return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
+}
+
+void main() {
+ vec3 N = normalize(vNormal);
+ vec3 V = normalize(cameraPos - vWorldPos);
+
+ // Fresnel (Schlick).
+ float f0 = 0.02;
+ float fres = f0 + (1.0 - f0) * pow(1.0 - max(dot(N, V), 0.0), 5.0);
+
+ // Refraction: depth-tinted water body, wobbled by the surface normal.
+ float depth01 = clamp((vWorldPos.z + 350.0) / 400.0, 0.0, 1.0);
+ float wob = (N.x + N.z) * 0.5;
+ vec3 shallow = vec3(0.10, 0.55, 0.60);
+ vec3 deep = vec3(0.02, 0.14, 0.28);
+ vec3 refractCol = mix(shallow, deep, clamp(depth01 + wob * 0.15, 0.0, 1.0));
+
+ // Reflection: sky gradient + reflected sun glow + broken-up specular glitter.
+ vec3 R = reflect(-V, N);
+ vec3 skyHorizon = vec3(0.80, 0.88, 0.98);
+ vec3 skyTop = vec3(0.30, 0.55, 0.95);
+ float skyT = clamp(R.y * 2.0, 0.0, 1.0);
+ vec3 reflectCol = mix(skyHorizon, skyTop, skyT);
+
+ float sunAmt = max(dot(R, sunDir), 0.0);
+ reflectCol += sunColor * pow(sunAmt, 8.0) * 0.6;
+ float sparkle = valueNoise(vWorldPos.xz * 0.5 + vec2(time * 1.3, time * 0.7));
+ float spec = pow(sunAmt, 200.0) * smoothstep(0.55, 0.9, sparkle);
+ reflectCol += sunColor * spec * 4.0;
+
+ vec3 color = mix(refractCol, reflectCol, fres);
+
+ // Horizon haze: hide the far straight edge of the plane by fading to sky.
+ float horizonFade = clamp((vWorldPos.z + 350.0) / 90.0, 0.0, 1.0);
+ color = mix(skyHorizon, color, horizonFade);
+
+ gl_FragColor = vec4(color, 1.0); // opaque -> occludes the sun below the waterline
+}
diff --git a/themes/src/_shaders/water.vert b/themes/src/_shaders/water.vert
new file mode 100644
index 0000000..7121ab1
--- /dev/null
+++ b/themes/src/_shaders/water.vert
@@ -0,0 +1,63 @@
+precision highp float;
+
+attribute vec2 position; // local (x, z) on the plane
+
+uniform mat4 projection;
+uniform mat4 view;
+uniform mat4 model;
+uniform float time;
+uniform float amplitude;
+
+varying vec3 vWorldPos;
+varying vec3 vNormal;
+
+float hash(vec2 p) {
+ p = fract(p * vec2(123.34, 456.21));
+ p += dot(p, p + 45.32);
+ return fract(p.x * p.y);
+}
+
+float valueNoise(vec2 p) {
+ vec2 i = floor(p);
+ vec2 f = fract(p);
+ float a = hash(i);
+ float b = hash(i + vec2(1.0, 0.0));
+ float c = hash(i + vec2(0.0, 1.0));
+ float d = hash(i + vec2(1.0, 1.0));
+ vec2 u = f * f * (3.0 - 2.0 * f);
+ return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
+}
+
+// Irregular height: non-harmonic directional sines plus two octaves of
+// scrolling value noise so it never reads as a single clean wave.
+float waveHeight(vec2 p, float t) {
+ float h = 0.0;
+ h += 0.30 * sin(dot(p, vec2(0.90, 0.30)) * 0.35 + t * 1.1);
+ h += 0.20 * sin(dot(p, vec2(-0.40, 1.00)) * 0.55 - t * 1.7);
+ h += 0.12 * sin(dot(p, vec2(0.70, -0.80)) * 0.90 + t * 2.3);
+ h += 0.08 * sin(dot(p, vec2(1.00, 0.60)) * 1.60 - t * 3.1);
+ h += 0.18 * (valueNoise(p * 0.25 + vec2(t * 0.15, t * 0.10)) - 0.5);
+ h += 0.09 * (valueNoise(p * 0.70 - vec2(t * 0.20, 0.0)) - 0.5);
+ return h;
+}
+
+void main() {
+ vec2 p = position;
+ float t = time;
+
+ float h = waveHeight(p, t) * amplitude;
+
+ // Analytic normal via central differences of the same height function.
+ float e = 2.0;
+ float hL = waveHeight(p - vec2(e, 0.0), t) * amplitude;
+ float hR = waveHeight(p + vec2(e, 0.0), t) * amplitude;
+ float hD = waveHeight(p - vec2(0.0, e), t) * amplitude;
+ float hU = waveHeight(p + vec2(0.0, e), t) * amplitude;
+ vec3 N = normalize(vec3(hL - hR, 2.0 * e, hD - hU));
+
+ vec4 worldPos = model * vec4(p.x, h, p.y, 1.0);
+ vWorldPos = worldPos.xyz;
+ vNormal = N; // model is translation-only, so no normal matrix needed
+
+ gl_Position = projection * view * worldPos;
+}