summaryrefslogtreecommitdiff
path: root/themes/src/shaders
diff options
context:
space:
mode:
authorMatt Kosarek <matt.kosarek@canonical.com>2026-07-08 09:07:55 -0400
committerMatt Kosarek <matt.kosarek@canonical.com>2026-07-08 09:07:55 -0400
commitc8938fe29132a11126013ed1b010c3092f5645e4 (patch)
treef6a6cd0603f25d51c08e302cc4342c28f9e10806 /themes/src/shaders
parent418396ee5100eda8f6bc036ea35dbbe44db2f91a (diff)
feature: improved summer scene
Diffstat (limited to 'themes/src/shaders')
-rw-r--r--themes/src/shaders/sky_frag.cpp81
-rw-r--r--themes/src/shaders/sky_frag.h4
-rw-r--r--themes/src/shaders/sky_vert.cpp13
-rw-r--r--themes/src/shaders/sky_vert.h4
-rw-r--r--themes/src/shaders/water_frag.cpp66
-rw-r--r--themes/src/shaders/water_frag.h4
-rw-r--r--themes/src/shaders/water_vert.cpp66
-rw-r--r--themes/src/shaders/water_vert.h4
8 files changed, 242 insertions, 0 deletions
diff --git a/themes/src/shaders/sky_frag.cpp b/themes/src/shaders/sky_frag.cpp
new file mode 100644
index 0000000..400f07c
--- /dev/null
+++ b/themes/src/shaders/sky_frag.cpp
@@ -0,0 +1,81 @@
+#include "sky_frag.h"
+
+const char* shader_sky_frag = "precision highp float; \n"
+" \n"
+"varying vec2 vUv; \n"
+" \n"
+"uniform float time; // seconds, for slow cloud drift \n"
+"uniform float horizon; // screen-space y of the water horizon (~0.5) \n"
+" \n"
+"float hash(vec2 p) { \n"
+" p = fract(p * vec2(123.34, 456.21)); \n"
+" p += dot(p, p + 45.32); \n"
+" return fract(p.x * p.y); \n"
+"} \n"
+" \n"
+"float valueNoise(vec2 p) { \n"
+" vec2 i = floor(p); \n"
+" vec2 f = fract(p); \n"
+" float a = hash(i); \n"
+" float b = hash(i + vec2(1.0, 0.0)); \n"
+" float c = hash(i + vec2(0.0, 1.0)); \n"
+" float d = hash(i + vec2(1.0, 1.0)); \n"
+" vec2 u = f * f * (3.0 - 2.0 * f); \n"
+" return mix(mix(a, b, u.x), mix(c, d, u.x), u.y); \n"
+"} \n"
+" \n"
+"float fbm(vec2 p) { \n"
+" float v = 0.0; \n"
+" float amp = 0.5; \n"
+" for (int i = 0; i < 4; i++) { \n"
+" v += amp * valueNoise(p); \n"
+" p *= 2.0; \n"
+" amp *= 0.5; \n"
+" } \n"
+" return v; \n"
+"} \n"
+" \n"
+"const vec3 SKY_HORIZON = vec3(0.80, 0.88, 0.98); // matches water horizon fade \n"
+"const vec3 SKY_TOP = vec3(0.22, 0.48, 0.86); // deeper zenith blue \n"
+"const vec3 CLOUD_COLOR = vec3(1.00, 0.98, 0.95); // white, slightly warm \n"
+" \n"
+"const float DEPTH_BIAS = 0.05; // caps frequency at the horizon (larger = gentler shrink) \n"
+"const float CLOUD_FREQ = 2.7; // overall cloud scale (larger = more, smaller clouds) \n"
+"const float X_STRETCH = 0.35; // < 1 stretches clouds horizontally -> wispy \n"
+"const float CLOUD_THRESH = 0.55; // coverage cutoff; higher = sparser sky \n"
+"const float CLOUD_SOFT = 0.22; // edge softness of the cloud mask \n"
+"const float CLOUD_OPACITY = 0.85; // max cloud whiteness \n"
+"const float DRIFT_SPEED = 0.03; // slow lateral drift (noise units / sec) \n"
+"const float H_FADE = 0.12; // band over which clouds fade in above horizon \n"
+" \n"
+"void main() { \n"
+" // Height above the water horizon: 0 at the waterline, (1 - horizon) at the top. \n"
+" float above = max(vUv.y - horizon, 0.0); \n"
+" \n"
+" // Vertical gradient. \n"
+" float g = clamp(above / (1.0 - horizon), 0.0, 1.0); \n"
+" vec3 col = mix(SKY_HORIZON, SKY_TOP, pow(g, 0.75)); \n"
+" float haze = 1.0 - smoothstep(0.0, 0.35, g); \n"
+" col += vec3(0.06, 0.04, 0.00) * haze; \n"
+" \n"
+" // Flat cloud-ceiling perspective: distance along the view ~ 1/above, so \n"
+" // features shrink AND compress vertically toward the horizon. \n"
+" float depth = 1.0 / (above + DEPTH_BIAS); \n"
+" vec2 q; \n"
+" q.x = (vUv.x - 0.5) * depth; \n"
+" q.y = depth; \n"
+" \n"
+" vec2 p = vec2(q.x * X_STRETCH, q.y) * CLOUD_FREQ; \n"
+" p.x += time * DRIFT_SPEED; \n"
+" \n"
+" float n = fbm(p); \n"
+" float cloud = smoothstep(CLOUD_THRESH, CLOUD_THRESH + CLOUD_SOFT, n); \n"
+" \n"
+" // Fade clouds into the haze right at the horizon. \n"
+" cloud *= smoothstep(0.0, H_FADE, above); \n"
+" \n"
+" col = mix(col, CLOUD_COLOR, cloud * CLOUD_OPACITY); \n"
+" \n"
+" gl_FragColor = vec4(col, 1.0); \n"
+"} \n"
+" \n";
diff --git a/themes/src/shaders/sky_frag.h b/themes/src/shaders/sky_frag.h
new file mode 100644
index 0000000..886b6eb
--- /dev/null
+++ b/themes/src/shaders/sky_frag.h
@@ -0,0 +1,4 @@
+#ifndef SHADER_SKY_FRAG
+#define SHADER_SKY_FRAG
+extern const char* shader_sky_frag;
+#endif
diff --git a/themes/src/shaders/sky_vert.cpp b/themes/src/shaders/sky_vert.cpp
new file mode 100644
index 0000000..b43aa73
--- /dev/null
+++ b/themes/src/shaders/sky_vert.cpp
@@ -0,0 +1,13 @@
+#include "sky_vert.h"
+
+const char* shader_sky_vert = "precision highp float; \n"
+" \n"
+"attribute vec2 position; // fullscreen quad, clip-space corners in [-1, 1] \n"
+" \n"
+"varying vec2 vUv; \n"
+" \n"
+"void main() { \n"
+" vUv = position * 0.5 + 0.5; // uv.y = 0 bottom, 1 top \n"
+" gl_Position = vec4(position, 0.0, 1.0); \n"
+"} \n"
+" \n";
diff --git a/themes/src/shaders/sky_vert.h b/themes/src/shaders/sky_vert.h
new file mode 100644
index 0000000..114fe63
--- /dev/null
+++ b/themes/src/shaders/sky_vert.h
@@ -0,0 +1,4 @@
+#ifndef SHADER_SKY_VERT
+#define SHADER_SKY_VERT
+extern const char* shader_sky_vert;
+#endif
diff --git a/themes/src/shaders/water_frag.cpp b/themes/src/shaders/water_frag.cpp
new file mode 100644
index 0000000..91c50f9
--- /dev/null
+++ b/themes/src/shaders/water_frag.cpp
@@ -0,0 +1,66 @@
+#include "water_frag.h"
+
+const char* shader_water_frag = "precision highp float; \n"
+" \n"
+"varying vec3 vWorldPos; \n"
+"varying vec3 vNormal; \n"
+" \n"
+"uniform vec3 cameraPos; \n"
+"uniform vec3 sunDir; // normalized direction from the water toward the sun \n"
+"uniform vec3 sunColor; \n"
+"uniform float time; \n"
+" \n"
+"float hash(vec2 p) { \n"
+" p = fract(p * vec2(123.34, 456.21)); \n"
+" p += dot(p, p + 45.32); \n"
+" return fract(p.x * p.y); \n"
+"} \n"
+" \n"
+"float valueNoise(vec2 p) { \n"
+" vec2 i = floor(p); \n"
+" vec2 f = fract(p); \n"
+" float a = hash(i); \n"
+" float b = hash(i + vec2(1.0, 0.0)); \n"
+" float c = hash(i + vec2(0.0, 1.0)); \n"
+" float d = hash(i + vec2(1.0, 1.0)); \n"
+" vec2 u = f * f * (3.0 - 2.0 * f); \n"
+" return mix(mix(a, b, u.x), mix(c, d, u.x), u.y); \n"
+"} \n"
+" \n"
+"void main() { \n"
+" vec3 N = normalize(vNormal); \n"
+" vec3 V = normalize(cameraPos - vWorldPos); \n"
+" \n"
+" // Fresnel (Schlick). \n"
+" float f0 = 0.02; \n"
+" float fres = f0 + (1.0 - f0) * pow(1.0 - max(dot(N, V), 0.0), 5.0); \n"
+" \n"
+" // Refraction: depth-tinted water body, wobbled by the surface normal. \n"
+" float depth01 = clamp((vWorldPos.z + 350.0) / 400.0, 0.0, 1.0); \n"
+" float wob = (N.x + N.z) * 0.5; \n"
+" vec3 shallow = vec3(0.10, 0.55, 0.60); \n"
+" vec3 deep = vec3(0.02, 0.14, 0.28); \n"
+" vec3 refractCol = mix(shallow, deep, clamp(depth01 + wob * 0.15, 0.0, 1.0)); \n"
+" \n"
+" // Reflection: sky gradient + reflected sun glow + broken-up specular glitter. \n"
+" vec3 R = reflect(-V, N); \n"
+" vec3 skyHorizon = vec3(0.80, 0.88, 0.98); \n"
+" vec3 skyTop = vec3(0.30, 0.55, 0.95); \n"
+" float skyT = clamp(R.y * 2.0, 0.0, 1.0); \n"
+" vec3 reflectCol = mix(skyHorizon, skyTop, skyT); \n"
+" \n"
+" float sunAmt = max(dot(R, sunDir), 0.0); \n"
+" reflectCol += sunColor * pow(sunAmt, 8.0) * 0.6; \n"
+" float sparkle = valueNoise(vWorldPos.xz * 0.5 + vec2(time * 1.3, time * 0.7)); \n"
+" float spec = pow(sunAmt, 200.0) * smoothstep(0.55, 0.9, sparkle); \n"
+" reflectCol += sunColor * spec * 4.0; \n"
+" \n"
+" vec3 color = mix(refractCol, reflectCol, fres); \n"
+" \n"
+" // Horizon haze: hide the far straight edge of the plane by fading to sky. \n"
+" float horizonFade = clamp((vWorldPos.z + 350.0) / 90.0, 0.0, 1.0); \n"
+" color = mix(skyHorizon, color, horizonFade); \n"
+" \n"
+" gl_FragColor = vec4(color, 1.0); // opaque -> occludes the sun below the waterline \n"
+"} \n"
+" \n";
diff --git a/themes/src/shaders/water_frag.h b/themes/src/shaders/water_frag.h
new file mode 100644
index 0000000..104cb04
--- /dev/null
+++ b/themes/src/shaders/water_frag.h
@@ -0,0 +1,4 @@
+#ifndef SHADER_WATER_FRAG
+#define SHADER_WATER_FRAG
+extern const char* shader_water_frag;
+#endif
diff --git a/themes/src/shaders/water_vert.cpp b/themes/src/shaders/water_vert.cpp
new file mode 100644
index 0000000..44dabd8
--- /dev/null
+++ b/themes/src/shaders/water_vert.cpp
@@ -0,0 +1,66 @@
+#include "water_vert.h"
+
+const char* shader_water_vert = "precision highp float; \n"
+" \n"
+"attribute vec2 position; // local (x, z) on the plane \n"
+" \n"
+"uniform mat4 projection; \n"
+"uniform mat4 view; \n"
+"uniform mat4 model; \n"
+"uniform float time; \n"
+"uniform float amplitude; \n"
+" \n"
+"varying vec3 vWorldPos; \n"
+"varying vec3 vNormal; \n"
+" \n"
+"float hash(vec2 p) { \n"
+" p = fract(p * vec2(123.34, 456.21)); \n"
+" p += dot(p, p + 45.32); \n"
+" return fract(p.x * p.y); \n"
+"} \n"
+" \n"
+"float valueNoise(vec2 p) { \n"
+" vec2 i = floor(p); \n"
+" vec2 f = fract(p); \n"
+" float a = hash(i); \n"
+" float b = hash(i + vec2(1.0, 0.0)); \n"
+" float c = hash(i + vec2(0.0, 1.0)); \n"
+" float d = hash(i + vec2(1.0, 1.0)); \n"
+" vec2 u = f * f * (3.0 - 2.0 * f); \n"
+" return mix(mix(a, b, u.x), mix(c, d, u.x), u.y); \n"
+"} \n"
+" \n"
+"// Irregular height: non-harmonic directional sines plus two octaves of \n"
+"// scrolling value noise so it never reads as a single clean wave. \n"
+"float waveHeight(vec2 p, float t) { \n"
+" float h = 0.0; \n"
+" h += 0.30 * sin(dot(p, vec2(0.90, 0.30)) * 0.35 + t * 1.1); \n"
+" h += 0.20 * sin(dot(p, vec2(-0.40, 1.00)) * 0.55 - t * 1.7); \n"
+" h += 0.12 * sin(dot(p, vec2(0.70, -0.80)) * 0.90 + t * 2.3); \n"
+" h += 0.08 * sin(dot(p, vec2(1.00, 0.60)) * 1.60 - t * 3.1); \n"
+" h += 0.18 * (valueNoise(p * 0.25 + vec2(t * 0.15, t * 0.10)) - 0.5); \n"
+" h += 0.09 * (valueNoise(p * 0.70 - vec2(t * 0.20, 0.0)) - 0.5); \n"
+" return h; \n"
+"} \n"
+" \n"
+"void main() { \n"
+" vec2 p = position; \n"
+" float t = time; \n"
+" \n"
+" float h = waveHeight(p, t) * amplitude; \n"
+" \n"
+" // Analytic normal via central differences of the same height function. \n"
+" float e = 2.0; \n"
+" float hL = waveHeight(p - vec2(e, 0.0), t) * amplitude; \n"
+" float hR = waveHeight(p + vec2(e, 0.0), t) * amplitude; \n"
+" float hD = waveHeight(p - vec2(0.0, e), t) * amplitude; \n"
+" float hU = waveHeight(p + vec2(0.0, e), t) * amplitude; \n"
+" vec3 N = normalize(vec3(hL - hR, 2.0 * e, hD - hU)); \n"
+" \n"
+" vec4 worldPos = model * vec4(p.x, h, p.y, 1.0); \n"
+" vWorldPos = worldPos.xyz; \n"
+" vNormal = N; // model is translation-only, so no normal matrix needed \n"
+" \n"
+" gl_Position = projection * view * worldPos; \n"
+"} \n"
+" \n";
diff --git a/themes/src/shaders/water_vert.h b/themes/src/shaders/water_vert.h
new file mode 100644
index 0000000..638b22b
--- /dev/null
+++ b/themes/src/shaders/water_vert.h
@@ -0,0 +1,4 @@
+#ifndef SHADER_WATER_VERT
+#define SHADER_WATER_VERT
+extern const char* shader_water_vert;
+#endif