aboutsummaryrefslogtreecommitdiffziptar.gz
path: root/viewer/js/shading.js
diff options
context:
space:
mode:
authorgodosa <godosa@godosa.eu>2026-10-07 00:14:38 +0200
committergodosa <godosa@godosa.eu>2026-10-07 00:14:38 +0200
commit3443c1c65e9f1753e1e656b35d08416c1fa298f2 (patch)
tree4e43236f460145a4d75d1b4616dcb7aa6ef08f51 /viewer/js/shading.js
downloadworldmap-viewer-3443c1c65e9f1753e1e656b35d08416c1fa298f2.tar.gz
worldmap-viewer-3443c1c65e9f1753e1e656b35d08416c1fa298f2.zip
worldmap-viewer: initial public history
Diffstat (limited to 'viewer/js/shading.js')
-rw-r--r--viewer/js/shading.js59
1 files changed, 59 insertions, 0 deletions
diff --git a/viewer/js/shading.js b/viewer/js/shading.js
new file mode 100644
index 0000000..7b07059
--- /dev/null
+++ b/viewer/js/shading.js
@@ -0,0 +1,59 @@
+// shading.js — fragment shading shared by both views and the deep-zoom tiles: base texture, optional over-layer,
+// then sun lighting (Sky on) or the plain v1 look (limb factor only).
+import * as THREE from 'three';
+import { R_KM } from './geo.js';
+import { HAZE_KM } from './atmosphere.js';
+
+export const SHADE_GLSL = /* glsl */ `
+uniform sampler2D map;
+uniform sampler2D map2;
+uniform float hasMap;
+uniform float mix2;
+uniform vec3 sunDir;
+uniform float sky;
+uniform vec3 camPos;
+uniform vec3 hazeCol;
+uniform float hazeAmt;
+uniform float hazeK;
+vec3 overColor(vec3 c, vec3 o, float k) {
+ float l = dot(c, vec3(0.299, 0.587, 0.114));
+ vec3 g = mix(c, vec3(l), min(1.0, 2.0 * k));
+ return mix(g, o * clamp(0.55 + 0.9 * l, 0.0, 1.0), k);
+}
+vec3 lightColor(vec2 uv, vec3 n, float limb) {
+ vec3 c = mix(vec3(0.16, 0.2, 0.28), texture2D(map, uv).rgb, hasMap);
+ if (mix2 > 0.0) c = overColor(c, texture2D(map2, uv).rgb, mix2);
+ if (sky < 0.5) return c * limb;
+ float cz = dot(normalize(n), sunDir);
+ float day = smoothstep(-0.1, 0.1, cz);
+ vec3 lit = c * (0.8 + 0.2 * clamp(cz, 0.0, 1.0));
+ vec3 night = c * vec3(0.24, 0.27, 0.36);
+ return mix(night, lit, day) * mix(1.0, limb, 0.4);
+}
+vec3 shadeColor(vec2 uv, vec3 n, float limb) { // near the ground, distance fades into the horizon colour
+ vec3 c = lightColor(uv, n, limb);
+ if (hazeAmt <= 0.0) return c;
+ return mix(c, hazeCol, hazeAmt * (1.0 - exp(-distance(n, camPos) * hazeK)));
+}`;
+
+export function shadeUniforms() {
+ return { map: { value: null }, map2: { value: null }, hasMap: { value: 0 }, mix2: { value: 0 },
+ sunDir: { value: new THREE.Vector3(1, 0, 0) }, sky: { value: 0 },
+ camPos: { value: new THREE.Vector3() }, hazeCol: { value: new THREE.Vector3(0.74, 0.83, 0.93) },
+ hazeAmt: { value: 0 }, hazeK: { value: R_KM / HAZE_KM } };
+}
+
+export function overMix(c, o, k) {
+ const l = 0.299 * c[0] + 0.587 * c[1] + 0.114 * c[2], d = Math.min(1, 2 * k), s = Math.min(1, Math.max(0, 0.55 + 0.9 * l));
+ return c.map((v, i) => { const g = v + (l - v) * d; return g + (o[i] * s - g) * k; });
+}
+
+export function applyOver(u, tex, op) {
+ u.map2.value = tex;
+ u.mix2.value = tex ? op : 0;
+}
+
+export function applySun(u, v) {
+ if (v) u.sunDir.value.set(v[0], v[1], v[2]);
+ u.sky.value = v ? 1 : 0;
+}