docs: add render diagrams and complete config examples
This commit is contained in:
1 parent
b9a77fbaa4
commit
d5fb1f12c4
3 files changed
+246
-139
No files matched your search
@@ -8,8 +8,8 @@ dropped into an iframe or kiosk browser and left running.
|
||||
|
||||
- **WebGL flight scene** (`vendor/clouds3d.js`): a 3D terrain mesh built from
|
||||
real elevation data (Copernicus DEM), a raymarched volumetric cloud deck,
|
||||
and a figure-eight flight path around the configured location with a
|
||||
vertical bob inside the 15-35 km flight band.
|
||||
optional round-world curvature, and a figure-eight flight path around the
|
||||
configured location with a vertical bob inside the 15-35 km flight band.
|
||||
- **One physical light model** shared by sky, clouds, contrails, aircraft and
|
||||
ground: direct beam through a Kasten-Young air mass with Rayleigh, ozone and
|
||||
aerosol extinction, diffuse skylight, moonlight, a starlight floor and aerial
|
||||
@@ -20,11 +20,12 @@ dropped into an iframe or kiosk browser and left running.
|
||||
- **Theme-tinted lighting**: each theme may pull the physical colours toward
|
||||
its own palette and set its own day/night exposure, without replacing the
|
||||
physics (`window.THEMES[...].lighting`).
|
||||
- **Shadows**: moving cloud shadows sampled from the same cloud field the sky
|
||||
renders, plus terrain self-shadowing over the DEM height field.
|
||||
- **Shadows**: moving cloud shadows sampled from the same wind-advected cloud
|
||||
field the sky renders, plus terrain self-shadowing over the DEM height field.
|
||||
- **Realistic night sky**: ~8700 stars from the Yale Bright Star Catalogue
|
||||
(points sized by magnitude, coloured by temperature), rotated at the sidereal
|
||||
rate for the site's latitude, a Milky Way band and a moon disc with a real
|
||||
rate for the site's latitude, a Milky Way band, approximate Keplerian planet
|
||||
points for Mercury..Pluto with planet colours, and a moon disc with a real
|
||||
lunar surface map: the terminator comes from the sun direction, so crescent,
|
||||
gibbous and full fall out of the geometry (sun and moon discs are drawn
|
||||
enlarged - `CONFIG.sun`/`CONFIG.moon` - while the lighting stays physical).
|
||||
@@ -37,7 +38,8 @@ dropped into an iframe or kiosk browser and left running.
|
||||
nodes (bigger towns get more and brighter dots). Both fade in light by light
|
||||
across twilight instead of switching as one block.
|
||||
- **Live weather** (Open-Meteo): current conditions plus a 4-day forecast
|
||||
widget; the weather code selects the cloud coverage and the colour mood.
|
||||
widget; the weather code selects the cloud coverage and the colour mood, and
|
||||
wind speed/direction advect the cloud field.
|
||||
- **Fully cached, offline-capable**: basemap tiles, the elevation grid, Overpass
|
||||
road/place cells, the merged road chains and the decoded settlement list live
|
||||
permanently in IndexedDB; the star catalogue is inlined. Once warm, the scene
|
||||
@@ -106,6 +108,138 @@ cache, which is the gentlest option for the upstreams. If a source is
|
||||
unreachable, the scene degrades instead of failing: an "OFFLINE"-labelled
|
||||
ground grid in place of basemap tiles.
|
||||
|
||||
## Render flow diagrams
|
||||
|
||||
The scene is a sequence of full-screen and geometry passes sharing one light
|
||||
state. The diagrams below describe the current pipeline.
|
||||
|
||||
### Frame pipeline
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[background.html] --> B[CONFIG + THEMES]
|
||||
A --> C[Open-Meteo weather]
|
||||
A --> D[SunCalc clock: sun, moon, sidereal time]
|
||||
A --> E[IndexedDB cache: tiles, DEM, Overpass]
|
||||
B --> F[clouds3dRender]
|
||||
C --> F
|
||||
D --> F
|
||||
E --> F
|
||||
|
||||
F --> G[Sky pass: gradient, stars, Milky Way, sun, moon]
|
||||
G --> H[Star catalogue points]
|
||||
H --> I[Planet points]
|
||||
G --> J[Terrain distance pass]
|
||||
J --> K[Terrain mesh pass]
|
||||
K --> L[City lights]
|
||||
L --> M[Car lights]
|
||||
M --> N[Optional atmosphere model]
|
||||
N --> O[Front haze]
|
||||
O --> P[Cloud raymarch]
|
||||
P --> Q[Aircraft]
|
||||
Q --> R[Contrails]
|
||||
```
|
||||
|
||||
### Weather and cloud calculation
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[Open-Meteo current/hourly] --> B[weather_code]
|
||||
A --> C[wind_speed_10m]
|
||||
A --> D[wind_direction_10m]
|
||||
B --> E[weather theme]
|
||||
B --> F[cloud coverage density]
|
||||
C --> G[wind speed in world units/s]
|
||||
D --> H[advection vector toward opposite bearing]
|
||||
F --> I[cloudDensity fBm]
|
||||
G --> I
|
||||
H --> I
|
||||
I --> J[raymarch cloud deck]
|
||||
J --> K[cloud colour and alpha]
|
||||
K --> L[sky/cloud pixels]
|
||||
K --> M[terrain cloud shadows]
|
||||
```
|
||||
|
||||
### Cloud shadows on terrain
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Sky as Sky/Cloud pass
|
||||
participant Cloud as cloudDensity()
|
||||
participant Wind as wind vector
|
||||
participant Terrain as Terrain shader
|
||||
participant Sun as Sun direction
|
||||
|
||||
Wind->>Cloud: offset cloud field over time
|
||||
Terrain->>Cloud: sample from ground point toward sun
|
||||
Cloud-->>Terrain: optical depth through cloud deck
|
||||
Terrain->>Terrain: darken direct sunlight by cloud optical depth
|
||||
Terrain->>Terrain: reduce skylight by cloudShadowAmbient
|
||||
Terrain-->>Screen: shaded ground patch under moving cloud
|
||||
```
|
||||
|
||||
### Terrain self-shadowing
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant T as Terrain fragment
|
||||
participant H as DEM height field
|
||||
participant Sun as Sun direction
|
||||
|
||||
T->>H: march from surface point toward sun
|
||||
H-->>T: terrain height samples
|
||||
T->>T: compare surface height with sampled terrain height
|
||||
T->>T: shadow = 0 if blocked, 1 if lit
|
||||
T-->>Screen: ridge/valley shading with terrainShadowFloor
|
||||
```
|
||||
|
||||
### Aircraft and contrails
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[OSM aerodromes] --> B[airport graph]
|
||||
B --> C[destination selection]
|
||||
C --> D[Bezier route: climb, cruise, descent]
|
||||
D --> E[aircraft mesh + night strobes]
|
||||
D --> F[eligible for contrail]
|
||||
F --> G[contrail ribbon geometry]
|
||||
G --> H[world-space fBm shader]
|
||||
H --> I[contrail pixels]
|
||||
E --> I
|
||||
```
|
||||
|
||||
### Roads, car lights and city lights
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Overpass road cells] --> B[road chains]
|
||||
B --> C[road slots]
|
||||
C --> D[traffic side lookup]
|
||||
D --> E[vehicle points]
|
||||
E --> F[distance fade + night ramp]
|
||||
F --> G[car light pixels]
|
||||
|
||||
H[Overpass place nodes] --> I[settlement list]
|
||||
I --> J[rank/population weighting]
|
||||
J --> K[city light clusters]
|
||||
K --> L[city light pixels]
|
||||
```
|
||||
|
||||
### Planets and stars
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[scene date] --> B[Keplerian planet positions]
|
||||
B --> C[geocentric ecliptic vector]
|
||||
C --> D[RA/Dec]
|
||||
D --> E[local sky direction]
|
||||
E --> F[planet points]
|
||||
|
||||
G[Yale star catalogue] --> H[RA/Dec]
|
||||
H --> I[sidereal rotation]
|
||||
I --> J[star points]
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
`config.js` is the reference: every key is documented in place, and unused
|
||||
@@ -125,13 +259,15 @@ Groups:
|
||||
| `ground.style` | `'satellite'` (ESRI World_Imagery) or `'streets'` (ESRI World_Street_Map) |
|
||||
| `orbit` | figure-eight path, `radiusKm`, direction, reorientation, `altBob` |
|
||||
| `fog.distanceKm` | distance haze (0/false = off) |
|
||||
| `clouds` | deck height (`top`/`bottom` in world units) and `density` per weather level |
|
||||
| `clouds` | deck height (`top`/`bottom` in world units), `density` per weather level, and `wind` motion from Open-Meteo |
|
||||
| `flights` | aircraft count, altitudes, speeds, destination weights, contrails, night strobes |
|
||||
| `terrain` | DEM mesh, `exaggeration`, `edgeFadeTiles`, `carLights`, `cityLights`, `wireframe` |
|
||||
| `terrain` | DEM mesh, `exaggeration`, edge fade/skirt, `outerDem`, `carLights`, `cityLights`, `wireframe` |
|
||||
| `carLights` | road width, light sizes, lane separation, traffic range/fade, `trafficSide`, spacing, speed, density, brightness |
|
||||
| `lights` | twilight switching window of every artificial light (`offDeg`, `onDeg`, `softDeg`) |
|
||||
| `atmosphere` | turbidity, moon/star gains, night floor, albedo/sky/air gains, haze residual, cloud albedo and cloud haze, cloud shadows, terrain shadows |
|
||||
| `atmosphere` | turbidity, moon/star gains, night floor, albedo/sky/air gains, haze blocks, cloud albedo/haze, cloud shadows, terrain shadows |
|
||||
| `stars` | star colour `tint` and `brightness` |
|
||||
| `planets` | planet points: `enabled`, `brightness`, `sizeScale`, `showPluto` |
|
||||
| `curvature` | round-world curvature: `enabled`, `earthRadiusKm`, `exaggeration` |
|
||||
| `sun` | `angularRadius` (disc size only, 12x physical by default) |
|
||||
| `moon` | disc size (`angularRadius`, 12x physical by default), `texture`, `lightGain`, `earthshine`, `limbDarkening`, `brightness`, `halo`, `flipU`/`flipV` |
|
||||
| `camera` | `aim` (`'off'` or `'moon'`), `aimEase`, `aimBob` |
|
||||
@@ -140,7 +276,7 @@ Groups:
|
||||
### World scale
|
||||
|
||||
1 world unit = one zoom-11 tile ≈ 12.9 km at 48.6°N. World axes are
|
||||
`+X = west`, `+Y = up`, `+Z = north`; the camera flies the 15-35 km band
|
||||
`+X = east`, `+Y = up`, `+Z = north`; the camera flies the 15-35 km band
|
||||
(`y ≈ 1.16-2.70`). Cloud deck heights, fog distance and orbit radius are all
|
||||
expressed in these units or in km where noted.
|
||||
|
||||
|
||||
@@ -23,18 +23,20 @@
|
||||
* ground basemap style
|
||||
* orbit flight path (figure eight or straight line)
|
||||
* fog distance haze
|
||||
* clouds cloud deck height + per-weather coverage
|
||||
* clouds cloud deck height, coverage and wind motion
|
||||
* flights civil aviation layer (aircraft + contrails)
|
||||
* terrain 3D ground, car lights, settlement lights
|
||||
* carLights tuning of the vehicle light layer
|
||||
* lights twilight switching of artificial lights
|
||||
* atmosphere physical light model + shadow/haze knobs
|
||||
* stars star catalogue tint and brightness
|
||||
* planets Keplerian planet points in the night sky
|
||||
* curvature round-world curvature for terrain, roads, lights and sky paths
|
||||
* day simulated day cycle or the real sun
|
||||
*
|
||||
* WORLD SCALE
|
||||
* 1 world unit = 1 zoom-11 tile ~ 12.9 km at 48.6 deg N.
|
||||
* World axes: +X = west, +Y = up, +Z = north (verified against the
|
||||
* World axes: +X = east, +Y = up, +Z = north (verified against the
|
||||
* basemap and the star frame). Camera flies a 15-35 km band (y ~ 1.16-2.70).
|
||||
*
|
||||
* TIME FORMAT TOKENS (own mini formatter, Moment.js-like names)
|
||||
@@ -50,11 +52,19 @@ window.CONFIG = {
|
||||
// Identity and UI
|
||||
// ------------------------------------------------------------------
|
||||
theme: 'ash', // 'ash' | 'nord' | 'gruvbox' (see window.THEMES)
|
||||
language: 'en', // 'en', 'de' - keys of the i18n.js dictionaries
|
||||
// theme: 'nord'
|
||||
// theme: 'gruvbox'
|
||||
language: 'en', // 'en', 'de', 'it', 'es', 'fr', 'ru'
|
||||
// language: 'de'
|
||||
timeFormat: 'DD. MMMM, YYYY ‒ HH:mm:SS',
|
||||
// timeFormat: 'YYYY-MM-DD HH:mm:ss'
|
||||
// timeFormat: 'dddd, DD. MMMM YYYY HH:mm'
|
||||
debug: 0, // 1 = debug panel + progress logs in the console
|
||||
// debug: 1
|
||||
credits: true, // false = hide the attribution line
|
||||
// credits: false
|
||||
units: { temperature: 'C' }, // 'F' for Fahrenheit
|
||||
// units: { temperature: 'F' }
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Rendering budget
|
||||
@@ -64,14 +74,14 @@ window.CONFIG = {
|
||||
// and upscaled with image-rendering: pixelated, so it reads as pixel
|
||||
// art instead of a blurry rescale. The DOM UI stays crisp at any value.
|
||||
// 1 = native resolution (sharpest, most expensive).
|
||||
renderScale: 0.5,
|
||||
renderScale: 0.5, // 1 native, 0.5 pixel-art 2x, 0.25 4x
|
||||
// Scene frame cap. All motion is time-based, so this only changes
|
||||
// smoothness, never speed. 0 = free running (vsync).
|
||||
maxFps: 30,
|
||||
maxFps: 30, // 0 = free running
|
||||
// MSAA on the WebGL framebuffer. Costs fill rate, and with renderScale
|
||||
// below 1 the pixel blocks dominate anyway - set false if the scene is
|
||||
// GPU bound. Read once at context creation, so a reload is needed.
|
||||
antialias: true,
|
||||
antialias: true, // false saves GPU fill rate
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Location
|
||||
@@ -82,6 +92,7 @@ window.CONFIG = {
|
||||
lat: 48.5667,
|
||||
lon: 13.4319
|
||||
// label: 'Passau' // overrides the reverse-geocoded name
|
||||
// lat: 51.5074, lon: -0.1278 // London example
|
||||
},
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
@@ -90,8 +101,9 @@ window.CONFIG = {
|
||||
// false = live Open-Meteo conditions (also used for the theme choice).
|
||||
// true = cycle sunny -> cloudy -> stormy -> night, useful to compare
|
||||
// all weather looks without waiting on the API.
|
||||
weatherSim: false,
|
||||
weatherSim: false, // true cycles sunny/cloudy/stormy/night
|
||||
weatherSimInterval: 30000, // ms per weather step when weatherSim is true
|
||||
// weatherSim: true, weatherSimInterval: 15000
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Tiles and caches
|
||||
@@ -101,15 +113,17 @@ window.CONFIG = {
|
||||
// ('background-tiles' / store 'tiles') and are never re-fetched once
|
||||
// cached: a warm cache renders fully offline.
|
||||
tiles: {
|
||||
expireDays: null, // e.g. 90 = re-fetch basemap tiles every 90 days
|
||||
expireDays: null, // null = never expire; e.g. 90 = re-fetch every 90 days
|
||||
debug: false // true = tile borders + N/S + x/y labels baked
|
||||
// into the ground texture (orientation debug)
|
||||
// tiles: { expireDays: 30, debug: true }
|
||||
},
|
||||
ground: {
|
||||
// 'satellite' = ESRI World_Imagery (aerial, no labels)
|
||||
// 'streets' = ESRI World_Street_Map (with place names)
|
||||
// Both are cached separately (cache id prefix 'sat/' vs plain).
|
||||
style: 'satellite'
|
||||
// style: 'streets'
|
||||
},
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
@@ -121,6 +135,8 @@ window.CONFIG = {
|
||||
orbit: {
|
||||
radiusKm: 60, // lobe tip reach (clamped ~190 km so the
|
||||
// tips plus the fog dome fit the mosaic)
|
||||
// radiusKm: 35 // tighter flight
|
||||
// radiusKm: 120 // wider flight, more terrain visible
|
||||
clockwise: true, // travel direction along the eight
|
||||
reorient: true, // false keeps the bearing across crossings
|
||||
// Vertical bobbing inside the 15-35 km band: centre 25 km, amp is
|
||||
@@ -135,6 +151,8 @@ window.CONFIG = {
|
||||
// ------------------------------------------------------------------
|
||||
fog: {
|
||||
distanceKm: 120 // fully saturated haze at this range; 0/false = off
|
||||
// distanceKm: 0 // no distance fog
|
||||
// distanceKm: 220 // deeper aerial perspective
|
||||
},
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
@@ -143,7 +161,7 @@ window.CONFIG = {
|
||||
// World units (1 unit ~ 12.9 km). Keep 'top' below the lowest flight
|
||||
// altitude so aircraft fly above the deck.
|
||||
clouds: {
|
||||
enabled: true,
|
||||
enabled: true, // false removes the volumetric cloud deck
|
||||
top: 1.0, // ~12.9 km
|
||||
bottom: -0.2, // ~-2.6 km (deck base slightly below terrain)
|
||||
// Coverage per weather level, 0 = clear, 1 = overcast. Only the
|
||||
@@ -158,9 +176,11 @@ window.CONFIG = {
|
||||
// bearing. speedScale exaggerates real advection so the motion is
|
||||
// visible at the world scale (1 unit ~ 12.9 km).
|
||||
wind: {
|
||||
speedScale: 80,
|
||||
minSpeed: 0.004,
|
||||
maxSpeed: 0.08
|
||||
speedScale: 80, // 0 = no wind motion, 40 slow, 120 fast
|
||||
minSpeed: 0.004, // world units/s floor when API wind is calm
|
||||
maxSpeed: 0.08 // world units/s ceiling for storm winds
|
||||
// wind: { speedScale: 0 } // static clouds
|
||||
// wind: { speedScale: 140, maxSpeed: 0.12 } // very visible motion
|
||||
}
|
||||
// density: { sunny: 0.05, cloudy: 0.9, stormy: 1.0, night: 0.2 }
|
||||
},
|
||||
@@ -199,7 +219,7 @@ window.CONFIG = {
|
||||
// Paths are Bezier curves resampled to arc length, flown as a full
|
||||
// profile: climb, cruise, descent, landing, ground hold, new leg.
|
||||
flights: {
|
||||
enabled: true,
|
||||
enabled: true, // false removes aircraft and contrails
|
||||
altitudeKm: 14, // cruise altitude
|
||||
climbKm: 100, // climb/descent run to and from cruise
|
||||
count: 21, // simultaneous aircraft (max 240)
|
||||
@@ -213,11 +233,12 @@ window.CONFIG = {
|
||||
wStrip: 1,
|
||||
// Contrails: contrailChance of the aircraft leaves a trail once
|
||||
// above contrailStartKm, visible for contrailLifeS seconds.
|
||||
contrailChance: 1.00,
|
||||
contrailStartKm: 4,
|
||||
contrailLifeS: 300,
|
||||
contrailChance: 1.00, // 0 = no contrails, 1 = every eligible jet
|
||||
contrailStartKm: 4, // start after this distance from the airport
|
||||
contrailLifeS: 300, // seconds before a trail disappears
|
||||
contrailWidthM: 1400, // full trail width
|
||||
contrailFadeKm: 300, // fully faded at this distance (ramp starts at 35 %)
|
||||
// contrailChance: 0.35, contrailLifeS: 120 // short sparse trails
|
||||
// Night contrast: a physically scaled contrail is a faint grey thread
|
||||
// that disappears at 4x pixel scale, so this is the night share of its
|
||||
// opacity (0.34 was the old value) and it also drives the gain on the
|
||||
@@ -243,15 +264,17 @@ window.CONFIG = {
|
||||
// height field the terrain shadows are cast against.
|
||||
terrain: {
|
||||
enabled: true, // false = flat plane (no DEM, no terrain shadows)
|
||||
// terrain: false // completely disable the 3D ground
|
||||
exaggeration: 8, // vertical scale (1 = real, nearly invisible here)
|
||||
edgeFadeTiles: 4, // soft rim at the mosaic border, in tiles (~13 km)
|
||||
edgeSkirtKm: 800, // coarse outer terrain pulled past the horizon
|
||||
edgeSkirtRings: 24, // coarse rings in the outer skirt
|
||||
edgeSkirtNoise: 0.28, // fallback height variation if outer DEM is off
|
||||
outerDem: {
|
||||
enabled: true,
|
||||
enabled: true, // false uses procedural fallback heights
|
||||
zoom: 7, // reduced-resolution terrarium zoom for the skirt
|
||||
maxMeters: 2500 // height normalization for skirt colors
|
||||
// outerDem: { enabled: false }
|
||||
},
|
||||
carLights: true, // moving vehicle lights on the real road network
|
||||
cityLights: true, // settlement lights from OSM place nodes
|
||||
@@ -264,6 +287,7 @@ window.CONFIG = {
|
||||
// Roads come from Overpass (motorway/trunk for the A-net, primary/
|
||||
// secondary for the side layer), cached per grid cell.
|
||||
carLights: {
|
||||
// All distances are real metres/km unless the name says Px.
|
||||
roadWidthM: 24, // real carriageway width of the road line
|
||||
bandPx: 1.2, // pixel floor of the road line
|
||||
bandBrightness: 0.10, // road line glow (the points are the main layer)
|
||||
@@ -284,12 +308,15 @@ window.CONFIG = {
|
||||
// Japan, Australia, India, southern Africa, ...), 'left'/'right' forces it.
|
||||
trafficSide: 'auto',
|
||||
dashM: 620, // mean vehicle spacing on motorways
|
||||
// (side roads use dashM * 2.8)
|
||||
// side roads use dashM * 2.4
|
||||
// dashM: 350 // denser traffic
|
||||
// dashM: 1200 // sparse traffic
|
||||
spreadKm: 45, // gaussian sigma around the motorway network
|
||||
spreadFloor: 0.30, // share that far side roads keep
|
||||
speed: 1.0, // flow speed multiplier
|
||||
density: 1.0, // vehicle density multiplier
|
||||
brightness: 1.3 // vehicle light intensity
|
||||
// speed: 2.0, density: 0.6, brightness: 1.0
|
||||
},
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
@@ -300,9 +327,10 @@ window.CONFIG = {
|
||||
// piece. offDeg +5 deg is about 30 min before sunset here, onDeg -6 deg
|
||||
// is civil twilight. In the morning the same thresholds switch off again.
|
||||
lights: {
|
||||
offDeg: 5,
|
||||
onDeg: -6,
|
||||
offDeg: 5, // sun altitude where lights start switching off
|
||||
onDeg: -6, // sun altitude where lights are fully on
|
||||
softDeg: 1.2 // width of the individual transition
|
||||
// offDeg: 8, onDeg: -4, softDeg: 2.0 // earlier, softer twilight
|
||||
},
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
@@ -325,7 +353,6 @@ window.CONFIG = {
|
||||
airGain: 0.55, // Rayleigh airlight strength (blue-biased)
|
||||
physicalSky: true, // Rayleigh sky scattering instead of pure theme gradient
|
||||
rayleighGain: 8.0, // exposure for the physical sky term
|
||||
distanceFog: false, // legacy aerial perspective is off
|
||||
haze: {
|
||||
enabled: false, // full-screen haze pass causes horizon/sky flicker
|
||||
heightKm: 100,
|
||||
@@ -336,12 +363,14 @@ window.CONFIG = {
|
||||
maxAlpha: 0.55
|
||||
},
|
||||
terrainHaze: {
|
||||
enabled: true,
|
||||
scaleHeightKm: 8.5,
|
||||
density: 0.22,
|
||||
gain: 1.0,
|
||||
maxAlpha: 0.65,
|
||||
color: [0.58, 0.64, 0.72]
|
||||
enabled: true, // terrain-distance based haze on the ground
|
||||
scaleHeightKm: 8.5, // exponential vertical falloff
|
||||
density: 0.22, // optical depth per world unit
|
||||
gain: 1.0, // overall multiplier
|
||||
maxAlpha: 0.65, // maximum haze opacity
|
||||
color: [0.58, 0.64, 0.72] // fallback colour; dynamic night tint overrides
|
||||
// terrainHaze: { enabled: false }
|
||||
// terrainHaze: { density: 0.35, maxAlpha: 0.80 }
|
||||
},
|
||||
airHaze: {
|
||||
enabled: false, // replaced by stable front haze using terrain distance
|
||||
@@ -352,27 +381,37 @@ window.CONFIG = {
|
||||
color: [0.58, 0.64, 0.72]
|
||||
},
|
||||
frontHaze: {
|
||||
enabled: true,
|
||||
enabled: true, // stable front haze pass using terrain distance
|
||||
scaleHeightKm: 8.5,
|
||||
density: 0.22,
|
||||
gain: 1.0,
|
||||
maxAlpha: 0.65,
|
||||
color: [0.58, 0.64, 0.72]
|
||||
// frontHaze: { enabled: false }
|
||||
// frontHaze: { density: 0.30, maxAlpha: 0.75 }
|
||||
},
|
||||
model: {
|
||||
enabled: false // legacy full atmosphere model remains off
|
||||
enabled: false // legacy full-screen atmosphere model
|
||||
// model: { enabled: true, heightKm: 80, density: 0.25 }
|
||||
},
|
||||
hazeResidual: 0.30, // surface colour surviving at the full fog distance
|
||||
cloudBrightness: 1.0, // cloud albedo (theme hue, brightness from the model)
|
||||
cloudHaze: 0.22, // share of the ground haze applied to the deck
|
||||
// cloudBrightness: 1.35 // brighter cloud tops
|
||||
// cloudHaze: 0.10 // clouds stay cleaner against the haze
|
||||
// Cloud shadows: the terrain samples the same cloud field as the sky pass.
|
||||
cloudShadows: true,
|
||||
cloudShadowDensity: 1.8, // optical depth through the deck
|
||||
cloudShadowFloor: 0.06, // darkest shade under a thick cloud
|
||||
cloudShadowAmbient: 0.65, // share of the skylight a deck also blocks
|
||||
// cloudShadows: false
|
||||
// cloudShadowDensity: 2.6 // stronger moving cloud shade
|
||||
// cloudShadowFloor: 0.18 // softer, less contrasty shade
|
||||
// Terrain self-shadowing over the DEM height field.
|
||||
terrainShadows: true,
|
||||
terrainShadowFloor: 0.42, // brightness a fully shadowed slope keeps (0 = black)
|
||||
// terrainShadows: false
|
||||
// terrainShadowFloor: 0.25 // deeper ridge shadows
|
||||
// Optional variants (leave commented out to use the defaults):
|
||||
// turbidity: 3.0 // hazy, warm, strongly reddened low sun
|
||||
// moonGain: 1.2 // bright full-moon nights
|
||||
@@ -388,6 +427,22 @@ window.CONFIG = {
|
||||
stars: {
|
||||
tint: 0.10, // 0 = pure white points, 1 = full blackbody colour
|
||||
brightness: 1.6 // overall glow of the catalogue points
|
||||
// stars: { tint: 0.35, brightness: 2.2 } // stronger colour and glow
|
||||
},
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Planets
|
||||
// ------------------------------------------------------------------
|
||||
// Approximate Keplerian positions for Mercury..Pluto, rendered as
|
||||
// larger coloured points in the night sky. Positions are geocentric and
|
||||
// use the same simulated clock as sun/moon/stars.
|
||||
planets: {
|
||||
enabled: true,
|
||||
brightness: 1.0, // 0.5 = subtle, 2.0 = clearly readable
|
||||
sizeScale: 1.0, // 0.6 = small, 1.4 = prominent
|
||||
showPluto: true // Pluto is faint; false removes it
|
||||
// planets: { enabled: false }
|
||||
// planets: { brightness: 1.6, sizeScale: 1.25, showPluto: false }
|
||||
},
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
@@ -395,8 +450,10 @@ window.CONFIG = {
|
||||
// ------------------------------------------------------------------
|
||||
curvature: {
|
||||
enabled: true,
|
||||
earthRadiusKm: 6371,
|
||||
exaggeration: 4.0
|
||||
earthRadiusKm: 6371, // physical Earth radius used for the bend
|
||||
exaggeration: 4.0 // 1 = physically true, 4 = visually readable
|
||||
// curvature: { enabled: false } // flat world
|
||||
// curvature: { exaggeration: 2.0 } // gentler horizon drop
|
||||
},
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
@@ -419,6 +476,7 @@ window.CONFIG = {
|
||||
// Below the horizon the view holds the moon's azimuth at the horizon.
|
||||
camera: {
|
||||
aim: 'off', // 'off' | 'moon'
|
||||
// aim: 'moon' // look at the moon while flying the path
|
||||
aimEase: 0.94, // 0 = instant turn, 0.99 = very slow
|
||||
aimBob: 0.25 // share of the altitude bob kept while aiming
|
||||
// camera: { aim: 'moon' } // look at the moon
|
||||
@@ -435,9 +493,7 @@ window.CONFIG = {
|
||||
day: {
|
||||
startAt: null, // null = strictly real time
|
||||
speed: 1 // virtual seconds per real second
|
||||
// day: { startAt: '2026-10-29T20:56', speed: 1 } // start at a chosen
|
||||
// // moment, real pace
|
||||
// day: { startAt: '2026-10-29T20:56', speed: 1440 } // accelerated
|
||||
// startAt: '2026-10-29T20:56', speed: 1440 // one simulated day per minute
|
||||
},
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
Vendored
+10
-95
@@ -2783,7 +2783,6 @@ var RAYLEIGH = [0.192, 0.451, 1.0];
|
||||
var ATMO_AIR_GAIN = (typeof ATMO.airGain === 'number') ? Math.max(0.05, ATMO.airGain) : 0.55;
|
||||
var ATMO_HAZE_RESIDUAL = (typeof ATMO.hazeResidual === 'number')
|
||||
? Math.max(0.02, Math.min(0.95, ATMO.hazeResidual)) : 0.30;
|
||||
var ATMO_DISTANCE_FOG = ATMO.distanceFog !== false;
|
||||
var ATMO_MODEL = ATMO.model || {};
|
||||
var HAZE_CFG = ATMO.haze || {};
|
||||
var ATMO_MODEL_ON = (typeof HAZE_CFG.enabled === 'boolean')
|
||||
@@ -5416,9 +5415,6 @@ var planeV = null, planeVbo = null, planeProg = null, planeU = null, planeA = nu
|
||||
// noise phase), alpha ramping up toward the head. By day the stripes are
|
||||
// sun-lit white; by night they stay visible as dimmed moonlit streaks
|
||||
// (reusing the car-lights night ramp), around 40 % strength.
|
||||
var ctBuf = null, ctVbo = null, ctVerts = 0;
|
||||
var ctProg = null, ctA = null, ctU = null;
|
||||
|
||||
var CT2_SEG = 18;
|
||||
var ct2Buf = null, ct2Vbo = null, ct2Verts = 0;
|
||||
var ct2Prog = null, ct2A = null, ct2U = null;
|
||||
@@ -5518,95 +5514,6 @@ var CT2_FRAG_SRC = [
|
||||
'}'
|
||||
].join('\n');
|
||||
|
||||
function _ctVert(x, y, z, u, v, s, p) {
|
||||
var i = ctVerts * 7;
|
||||
ctBuf[i] = x; ctBuf[i + 1] = y; ctBuf[i + 2] = z;
|
||||
ctBuf[i + 3] = u; ctBuf[i + 4] = v; ctBuf[i + 5] = s; ctBuf[i + 6] = p;
|
||||
ctVerts++;
|
||||
}
|
||||
|
||||
var CT_VERT_SRC = [
|
||||
'attribute vec3 aPos;',
|
||||
'attribute float aU;', // 0 tail .. 1 head
|
||||
'attribute float aV;', // -1 .. +1 across the ribbon
|
||||
'attribute float aS;', // per-trail strength (gate x day x fade)',
|
||||
'attribute float aP;', // per-trail noise phase
|
||||
'uniform mat4 uProj;',
|
||||
'uniform mat4 uView;',
|
||||
'uniform vec3 uCamPos;',
|
||||
'uniform float uEarthRadius;',
|
||||
'uniform float uCurvatureOn;',
|
||||
'varying float vU;',
|
||||
'varying float vV;',
|
||||
'varying float vS;',
|
||||
'varying float vP;',
|
||||
'varying vec3 vWorld;',
|
||||
'void main() {',
|
||||
'vU = aU; vV = aV; vS = aS; vP = aP;',
|
||||
'vec3 pos = aPos;',
|
||||
'if (uCurvatureOn > 0.5) {',
|
||||
'vec2 d = pos.xz - uCamPos.xz;',
|
||||
'pos.y -= dot(d, d) / (2.0 * max(1.0, uEarthRadius));',
|
||||
'}',
|
||||
'vWorld = pos;',
|
||||
'gl_Position = uProj * uView * vec4(pos, 1.0);',
|
||||
'}'
|
||||
].join('\n');
|
||||
|
||||
var CT_FRAG_SRC = [
|
||||
'precision mediump float;',
|
||||
'uniform vec3 uSunColor;',
|
||||
'uniform float uSunInt;',
|
||||
'uniform vec3 uMoonColor;',
|
||||
'uniform float uMoonInt;',
|
||||
'uniform float uSkyAmb;',
|
||||
'uniform float uStarAmb;',
|
||||
'uniform float uNightBoost;', // extra gain on the moon/star terms
|
||||
'uniform vec3 uSunDir;',
|
||||
'uniform vec3 uCamPos;',
|
||||
'varying float vU;',
|
||||
'varying float vV;',
|
||||
'varying float vS;',
|
||||
'varying float vP;',
|
||||
'varying vec3 vWorld;',
|
||||
'void main() {',
|
||||
// Procedural mip: a contrail far away is a handful of pixels wide, so
|
||||
// its along-stripe density and its edge wobble are higher frequency
|
||||
// than the pixel grid can carry - that is the shimmer. Both fade to
|
||||
// their mean with distance, which leaves a steady faint stripe.
|
||||
'float cDist = length(vWorld - uCamPos);',
|
||||
'float cSoft = smoothstep(9.0, 22.0, cDist);',
|
||||
// density patches drifting along the stripe
|
||||
'float along = vU * 26.0 + vP * 31.0;',
|
||||
'float dens = 0.62 + 0.38 * sin(along) * sin(along * 2.7 + 1.3);',
|
||||
'dens = mix(dens, 0.62, cSoft);',
|
||||
'if (dens < 0.0) dens = 0.0;',
|
||||
// eroded, uneven edges: the stripe narrows and widens along u
|
||||
'float wob = 0.55 + 0.45 * (0.5 + 0.5 * sin(along * 3.1 + 7.0));',
|
||||
'wob = mix(wob, 0.78, cSoft);',
|
||||
'float side = abs(vV);',
|
||||
'float edge = 1.0 - smoothstep(wob * 0.22, wob, side);',
|
||||
// older tail also thins out across its width
|
||||
'edge *= 0.45 + 0.55 * pow(vU, 0.6);',
|
||||
'if (edge <= 0.0) discard;',
|
||||
'float a = vS * pow(vU, 1.15) * 1.15 * dens * edge;',
|
||||
'if (a <= 0.004) discard;',
|
||||
// A contrail is a cloud: sunlit head-on, moonlit at night, and on a
|
||||
// dark starlit night the diffuse starlight keeps it faintly visible
|
||||
// instead of a hard white stripe on black.
|
||||
'vec3 vd = normalize(vWorld - uCamPos);',
|
||||
'float cosT = dot(vd, -uSunDir);',
|
||||
'float phase = 0.35 + 0.65 * pow(max(0.0, cosT), 2.0);',
|
||||
// Same multipliers as the cloud deck, so the contrail/cloud
|
||||
// brightness ratio at night is the same as in daylight.
|
||||
'vec3 light = uSunColor * uSunInt * phase * 1.25',
|
||||
' + (uMoonColor * uMoonInt * 3.0',
|
||||
' + max(vec3(uSkyAmb), uStarAmb * vec3(0.75, 0.85, 1.0)) * 1.7)',
|
||||
' * uNightBoost;',
|
||||
'gl_FragColor = vec4(vec3(0.95, 0.96, 1.0) * light, a);',
|
||||
'}'
|
||||
].join('\n');
|
||||
|
||||
function decodePlaneVerts() {
|
||||
if (planeV || !window.__planeVerts) return;
|
||||
try {
|
||||
@@ -5672,6 +5579,12 @@ function planetHeliocentric(p, d) {
|
||||
var z = r * Math.sin(u) * Math.sin(i);
|
||||
return [x, y, z];
|
||||
}
|
||||
var PLANET_CFG = (window.CONFIG && window.CONFIG.planets) || {};
|
||||
var PLANETS_ON = PLANET_CFG.enabled !== false;
|
||||
var PLANET_BRIGHT = (typeof PLANET_CFG.brightness === 'number') ? Math.max(0, PLANET_CFG.brightness) : 1.0;
|
||||
var PLANET_SIZE_SCALE = (typeof PLANET_CFG.sizeScale === 'number') ? Math.max(0.2, Math.min(2.0, PLANET_CFG.sizeScale)) : 1.0;
|
||||
var PLANET_SHOW_PLUTO = PLANET_CFG.showPluto !== false;
|
||||
|
||||
function updatePlanetPoints(gl, date) {
|
||||
if (!gl || !date) return;
|
||||
var d = (date.getTime() - Date.UTC(2000, 0, 1, 12, 0, 0)) / 86400000;
|
||||
@@ -5683,6 +5596,8 @@ function updatePlanetPoints(gl, date) {
|
||||
var ceps = Math.cos(eps), seps = Math.sin(eps);
|
||||
for (var pi = 0; pi < PLANET_ELEMENTS.length; pi++) {
|
||||
var p = PLANET_ELEMENTS[pi];
|
||||
if (!PLANETS_ON) continue;
|
||||
if (!PLANET_SHOW_PLUTO && p.name === 'Pluto') continue;
|
||||
var helio = planetHeliocentric(p, d);
|
||||
var gx = helio[0] - earth[0];
|
||||
var gy = helio[1] - earth[1];
|
||||
@@ -5708,9 +5623,9 @@ function updatePlanetPoints(gl, date) {
|
||||
mag = mag + 5 * Math.log10(Math.max(1e-6, rGeo * rSun));
|
||||
mag = Math.max(-5.0, Math.min(16.0, mag));
|
||||
var bright = p.bright * Math.max(0.12, Math.min(1.25, Math.pow(2.512, -mag * 0.35)));
|
||||
data[di++] = dx; data[di++] = dy; data[di++] = dz; data[di++] = p.sizeCode;
|
||||
data[di++] = dx; data[di++] = dy; data[di++] = dz; data[di++] = p.sizeCode * PLANET_SIZE_SCALE;
|
||||
data[di++] = p.color[0]; data[di++] = p.color[1]; data[di++] = p.color[2];
|
||||
data[di++] = bright;
|
||||
data[di++] = bright * PLANET_BRIGHT;
|
||||
count++;
|
||||
}
|
||||
if (!planetVbo) planetVbo = gl.createBuffer();
|
||||
|
||||
Reference in new issue
Block a user