clouds: advect cloud field with Open-Meteo wind
This commit is contained in:
1 parent
0d8a5f93d3
commit
45e35982da
3 files changed
+73
-16
No files matched your search
Vendored
+34
-11
@@ -60,6 +60,7 @@ var FRAG_SRC = [
|
||||
'precision highp float;',
|
||||
'uniform vec2 uResolution;',
|
||||
'uniform float uTime;',
|
||||
'uniform vec3 uWind;',
|
||||
'uniform sampler2D uGround;',
|
||||
'uniform vec2 uGroundCenter;', // current mosaic centre (world units)
|
||||
'uniform vec2 uGroundSize;', // mosaic side extents (canvas tiles: W x H)
|
||||
@@ -203,13 +204,13 @@ var FRAG_SRC = [
|
||||
'}',
|
||||
'float cloudDensity(vec3 p, float baseThresh, float soft) {',
|
||||
'float py = p.y + earthDrop(p.xz);',
|
||||
'vec3 cp = vec3(p.x, py, p.z);',
|
||||
'float n = fbm3(cp * 0.22 + vec3(0.0, 0.0, uTime * 0.05));',
|
||||
'vec3 cp = vec3(p.x, py, p.z) + uWind * uTime;',
|
||||
'float n = fbm3(cp * 0.22 + vec3(0.0, 0.0, uTime * 0.02));',
|
||||
// The detail octave weighs at most 0.20 and fades to zero with
|
||||
// distance; past soft = 0.95 it contributes under 1 %, so the whole
|
||||
// 4-octave lookup is skipped for the (numerous) far samples.
|
||||
'if (soft < 0.75) {',
|
||||
'float d = fbm3(cp * 1.80 + vec3(uTime * 0.045, 7.3, uTime * 0.035));',
|
||||
'float d = fbm3(cp * 1.80 + vec3(uTime * 0.015, 7.3, uTime * 0.012));',
|
||||
'n = n + d * mix(0.22, 0.0, soft / 0.75);',
|
||||
'}',
|
||||
// Cloud layer between uCloudBot and uCloudTop, densest in the
|
||||
@@ -397,10 +398,10 @@ var FRAG_SRC = [
|
||||
'return vec2((-b - sq) / (2.0 * a), (-b + sq) / (2.0 * a));',
|
||||
'}',
|
||||
'float cloudDensitySpherical(vec3 p, float alt, float baseThresh, float soft) {',
|
||||
'vec3 q = vec3(p.x, alt, p.z);',
|
||||
'float n = fbm3(q * 0.22 + vec3(0.0, 0.0, uTime * 0.05));',
|
||||
'vec3 q = vec3(p.x, alt, p.z) + uWind * uTime;',
|
||||
'float n = fbm3(q * 0.22 + vec3(0.0, 0.0, uTime * 0.02));',
|
||||
'if (soft < 0.75) {',
|
||||
'float d = fbm3(q * 1.80 + vec3(uTime * 0.045, 7.3, uTime * 0.035));',
|
||||
'float d = fbm3(q * 1.80 + vec3(uTime * 0.015, 7.3, uTime * 0.012));',
|
||||
'n = n + d * mix(0.22, 0.0, soft / 0.75);',
|
||||
'}',
|
||||
'float h = clamp((alt - uCloudBot) / max(0.01, uCloudTop - uCloudBot), 0.0, 1.0);',
|
||||
@@ -852,13 +853,13 @@ var CLOUD_SAMPLER_GLSL = [
|
||||
'}',
|
||||
'float cloudDensity(vec3 p, float baseThresh, float soft) {',
|
||||
'float py = p.y + earthDrop(p.xz);',
|
||||
'vec3 cp = vec3(p.x, py, p.z);',
|
||||
'float n = fbm3(cp * 0.22 + vec3(0.0, 0.0, uTime * 0.05));',
|
||||
'vec3 cp = vec3(p.x, py, p.z) + uWind * uTime;',
|
||||
'float n = fbm3(cp * 0.22 + vec3(0.0, 0.0, uTime * 0.02));',
|
||||
// The detail octave weighs at most 0.20 and fades to zero with
|
||||
// distance; past soft = 0.95 it contributes under 1 %, so the whole
|
||||
// 4-octave lookup is skipped for the (numerous) far samples.
|
||||
'if (soft < 0.75) {',
|
||||
'float d = fbm3(cp * 1.80 + vec3(uTime * 0.045, 7.3, uTime * 0.035));',
|
||||
'float d = fbm3(cp * 1.80 + vec3(uTime * 0.015, 7.3, uTime * 0.012));',
|
||||
'n = n + d * mix(0.22, 0.0, soft / 0.75);',
|
||||
'}',
|
||||
'float h = clamp((py - uCloudBot) / (uCloudTop - uCloudBot), 0.0, 1.0);',
|
||||
@@ -885,6 +886,7 @@ var TERRAIN_FRAG_SRC = [
|
||||
'uniform vec3 uHorizonColor;', // fog colour taken from the same light model
|
||||
'uniform float uStarAmb;', // diffuse starlight + airglow (night only)
|
||||
'uniform float uTime;', // must match the sky pass: same cloud field
|
||||
'uniform vec3 uWind;', // cloud advection vector, world units / s
|
||||
'uniform float uCloudBot;',
|
||||
'uniform float uCloudTop;',
|
||||
'uniform float uDensity;', // cloud coverage, same as the sky pass
|
||||
@@ -1087,6 +1089,7 @@ function init(canvas) {
|
||||
var aPos = gl.getAttribLocation(prog, 'aPos');
|
||||
var uRes = gl.getUniformLocation(prog, 'uResolution');
|
||||
var uTime = gl.getUniformLocation(prog, 'uTime');
|
||||
var uWind = gl.getUniformLocation(prog, 'uWind');
|
||||
var uGround = gl.getUniformLocation(prog, 'uGround');
|
||||
var uGroundCenter = gl.getUniformLocation(prog, 'uGroundCenter');
|
||||
var uGroundSize = gl.getUniformLocation(prog, 'uGroundSize');
|
||||
@@ -1223,6 +1226,7 @@ function init(canvas) {
|
||||
var terrainUFarPlane = terrainProg ? gl.getUniformLocation(terrainProg, 'uFarPlane') : null;
|
||||
var terrainUstarAmb = terrainProg ? gl.getUniformLocation(terrainProg, 'uStarAmb') : null;
|
||||
var terrainUtime = terrainProg ? gl.getUniformLocation(terrainProg, 'uTime') : null;
|
||||
var terrainUwind = terrainProg ? gl.getUniformLocation(terrainProg, 'uWind') : null;
|
||||
var terrainUcloudbot = terrainProg ? gl.getUniformLocation(terrainProg, 'uCloudBot') : null;
|
||||
var terrainUcloudtop = terrainProg ? gl.getUniformLocation(terrainProg, 'uCloudTop') : null;
|
||||
var terrainUdensity = terrainProg ? gl.getUniformLocation(terrainProg, 'uDensity') : null;
|
||||
@@ -1250,7 +1254,7 @@ function init(canvas) {
|
||||
return {
|
||||
gl: gl, prog: prog, buf: buf, aPos: aPos,
|
||||
blackTex: blackTex,
|
||||
uRes: uRes, uTime: uTime, uGround: uGround,
|
||||
uRes: uRes, uTime: uTime, uWind: uWind, uGround: uGround,
|
||||
uGroundCenter: uGroundCenter, uGroundSize: uGroundSize,
|
||||
uCorridorRot: uCorridorRot,
|
||||
uViewProjInv: uViewProjInv,
|
||||
@@ -1314,7 +1318,7 @@ function init(canvas) {
|
||||
uHazeMaxAlpha: terrainUHazeMaxAlpha, uHazeColor: terrainUHazeColor,
|
||||
uDistancePassOn: terrainUDistancePass, uFarPlane: terrainUFarPlane,
|
||||
uStarAmb: terrainUstarAmb,
|
||||
uTime: terrainUtime, uCloudBot: terrainUcloudbot,
|
||||
uTime: terrainUtime, uWind: terrainUwind, uCloudBot: terrainUcloudbot,
|
||||
uCloudTop: terrainUcloudtop, uDensity: terrainUdensity,
|
||||
uCloudShadowOn: terrainUcloudshadow,
|
||||
uCloudShadowDensity: terrainUcsDens,
|
||||
@@ -1435,6 +1439,22 @@ if (window.CONFIG && window.CONFIG.clouds) {
|
||||
CLOUD_TOP = Math.max(0.2, Math.min(CLOUD_TOP, 2.0));
|
||||
CLOUD_BOT = Math.min(CLOUD_BOT, CLOUD_TOP - 0.4);
|
||||
var CLOUDS_ON = !(window.CONFIG && window.CONFIG.clouds && window.CONFIG.clouds.enabled === false);
|
||||
var CLOUD_WIND_CFG = (window.CONFIG && window.CONFIG.clouds && window.CONFIG.clouds.wind) || {};
|
||||
var CLOUD_WIND_SCALE = (typeof CLOUD_WIND_CFG.speedScale === 'number') ? Math.max(0, CLOUD_WIND_CFG.speedScale) : 80;
|
||||
var CLOUD_WIND_MIN = (typeof CLOUD_WIND_CFG.minSpeed === 'number') ? Math.max(0, CLOUD_WIND_CFG.minSpeed) : 0.004;
|
||||
var CLOUD_WIND_MAX = (typeof CLOUD_WIND_CFG.maxSpeed === 'number') ? Math.max(0, CLOUD_WIND_CFG.maxSpeed) : 0.08;
|
||||
function cloudWindVector() {
|
||||
var w = window.__currentWind || {};
|
||||
var speedKmh = Number(w.speedKmh || 0);
|
||||
var dirDeg = Number(w.dirDeg || 0);
|
||||
var speed = speedKmh * CLOUD_WIND_SCALE / (KM_PER_TILE * 3600);
|
||||
speed = Math.max(CLOUD_WIND_MIN, Math.min(CLOUD_WIND_MAX, speed));
|
||||
// Open-Meteo wind_direction_10m is the compass bearing the wind blows
|
||||
// FROM. Clouds advect toward the opposite bearing. World +X = east,
|
||||
// +Z = north, bearing 0 = north and clockwise.
|
||||
var rad = (dirDeg + 180) * Math.PI / 180;
|
||||
return [Math.sin(rad) * speed, 0.0, Math.cos(rad) * speed];
|
||||
}
|
||||
|
||||
// Terrain elevation grid (CONFIG.terrain). Heights come from Mapzen/
|
||||
// TILEZEN "terrarium" tiles (Copernicus DEM) at ELEV_Z, fetched once
|
||||
@@ -6130,6 +6150,8 @@ window.clouds3dRender = function(target) {
|
||||
gl.uniform2f(s.uRes, canvas.width, canvas.height);
|
||||
var now = performance.now() / 1000;
|
||||
gl.uniform1f(s.uTime, now);
|
||||
var _cloudWind = cloudWindVector();
|
||||
gl.uniform3f(s.uWind, _cloudWind[0], _cloudWind[1], _cloudWind[2]);
|
||||
|
||||
var pal = window.__currentPalette;
|
||||
if (!pal) {
|
||||
@@ -6485,6 +6507,7 @@ window.clouds3dRender = function(target) {
|
||||
// sky pass (same noise, same uTime, same coverage) and marches from
|
||||
// the surface towards the sun through the deck.
|
||||
gl.uniform1f(terr.uTime, now);
|
||||
gl.uniform3f(terr.uWind, _cloudWind[0], _cloudWind[1], _cloudWind[2]);
|
||||
gl.uniform1f(terr.uCloudBot, CLOUD_BOT);
|
||||
gl.uniform1f(terr.uCloudTop, CLOUD_TOP);
|
||||
gl.uniform1f(terr.uDensity, density);
|
||||
|
||||
Reference in new issue
Block a user