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
|
- **WebGL flight scene** (`vendor/clouds3d.js`): a 3D terrain mesh built from
|
||||||
real elevation data (Copernicus DEM), a raymarched volumetric cloud deck,
|
real elevation data (Copernicus DEM), a raymarched volumetric cloud deck,
|
||||||
and a figure-eight flight path around the configured location with a
|
optional round-world curvature, and a figure-eight flight path around the
|
||||||
vertical bob inside the 15-35 km flight band.
|
configured location with a vertical bob inside the 15-35 km flight band.
|
||||||
- **One physical light model** shared by sky, clouds, contrails, aircraft and
|
- **One physical light model** shared by sky, clouds, contrails, aircraft and
|
||||||
ground: direct beam through a Kasten-Young air mass with Rayleigh, ozone and
|
ground: direct beam through a Kasten-Young air mass with Rayleigh, ozone and
|
||||||
aerosol extinction, diffuse skylight, moonlight, a starlight floor and aerial
|
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
|
- **Theme-tinted lighting**: each theme may pull the physical colours toward
|
||||||
its own palette and set its own day/night exposure, without replacing the
|
its own palette and set its own day/night exposure, without replacing the
|
||||||
physics (`window.THEMES[...].lighting`).
|
physics (`window.THEMES[...].lighting`).
|
||||||
- **Shadows**: moving cloud shadows sampled from the same cloud field the sky
|
- **Shadows**: moving cloud shadows sampled from the same wind-advected cloud
|
||||||
renders, plus terrain self-shadowing over the DEM height field.
|
field the sky renders, plus terrain self-shadowing over the DEM height field.
|
||||||
- **Realistic night sky**: ~8700 stars from the Yale Bright Star Catalogue
|
- **Realistic night sky**: ~8700 stars from the Yale Bright Star Catalogue
|
||||||
(points sized by magnitude, coloured by temperature), rotated at the sidereal
|
(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,
|
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
|
gibbous and full fall out of the geometry (sun and moon discs are drawn
|
||||||
enlarged - `CONFIG.sun`/`CONFIG.moon` - while the lighting stays physical).
|
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
|
nodes (bigger towns get more and brighter dots). Both fade in light by light
|
||||||
across twilight instead of switching as one block.
|
across twilight instead of switching as one block.
|
||||||
- **Live weather** (Open-Meteo): current conditions plus a 4-day forecast
|
- **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
|
- **Fully cached, offline-capable**: basemap tiles, the elevation grid, Overpass
|
||||||
road/place cells, the merged road chains and the decoded settlement list live
|
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
|
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
|
unreachable, the scene degrades instead of failing: an "OFFLINE"-labelled
|
||||||
ground grid in place of basemap tiles.
|
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
|
## Configuration
|
||||||
|
|
||||||
`config.js` is the reference: every key is documented in place, and unused
|
`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) |
|
| `ground.style` | `'satellite'` (ESRI World_Imagery) or `'streets'` (ESRI World_Street_Map) |
|
||||||
| `orbit` | figure-eight path, `radiusKm`, direction, reorientation, `altBob` |
|
| `orbit` | figure-eight path, `radiusKm`, direction, reorientation, `altBob` |
|
||||||
| `fog.distanceKm` | distance haze (0/false = off) |
|
| `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 |
|
| `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 |
|
| `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`) |
|
| `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` |
|
| `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) |
|
| `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` |
|
| `moon` | disc size (`angularRadius`, 12x physical by default), `texture`, `lightGain`, `earthshine`, `limbDarkening`, `brightness`, `halo`, `flipU`/`flipV` |
|
||||||
| `camera` | `aim` (`'off'` or `'moon'`), `aimEase`, `aimBob` |
|
| `camera` | `aim` (`'off'` or `'moon'`), `aimEase`, `aimBob` |
|
||||||
@@ -140,7 +276,7 @@ Groups:
|
|||||||
### World scale
|
### World scale
|
||||||
|
|
||||||
1 world unit = one zoom-11 tile ≈ 12.9 km at 48.6°N. World axes are
|
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
|
(`y ≈ 1.16-2.70`). Cloud deck heights, fog distance and orbit radius are all
|
||||||
expressed in these units or in km where noted.
|
expressed in these units or in km where noted.
|
||||||
|
|
||||||
|
|||||||
@@ -23,18 +23,20 @@
|
|||||||
* ground basemap style
|
* ground basemap style
|
||||||
* orbit flight path (figure eight or straight line)
|
* orbit flight path (figure eight or straight line)
|
||||||
* fog distance haze
|
* fog distance haze
|
||||||
* clouds cloud deck height + per-weather coverage
|
* clouds cloud deck height, coverage and wind motion
|
||||||
* flights civil aviation layer (aircraft + contrails)
|
* flights civil aviation layer (aircraft + contrails)
|
||||||
* terrain 3D ground, car lights, settlement lights
|
* terrain 3D ground, car lights, settlement lights
|
||||||
* carLights tuning of the vehicle light layer
|
* carLights tuning of the vehicle light layer
|
||||||
* lights twilight switching of artificial lights
|
* lights twilight switching of artificial lights
|
||||||
* atmosphere physical light model + shadow/haze knobs
|
* atmosphere physical light model + shadow/haze knobs
|
||||||
* stars star catalogue tint and brightness
|
* 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
|
* day simulated day cycle or the real sun
|
||||||
*
|
*
|
||||||
* WORLD SCALE
|
* WORLD SCALE
|
||||||
* 1 world unit = 1 zoom-11 tile ~ 12.9 km at 48.6 deg N.
|
* 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).
|
* 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)
|
* TIME FORMAT TOKENS (own mini formatter, Moment.js-like names)
|
||||||
@@ -50,11 +52,19 @@ window.CONFIG = {
|
|||||||
// Identity and UI
|
// Identity and UI
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
theme: 'ash', // 'ash' | 'nord' | 'gruvbox' (see window.THEMES)
|
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: '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: 0, // 1 = debug panel + progress logs in the console
|
||||||
|
// debug: 1
|
||||||
credits: true, // false = hide the attribution line
|
credits: true, // false = hide the attribution line
|
||||||
|
// credits: false
|
||||||
units: { temperature: 'C' }, // 'F' for Fahrenheit
|
units: { temperature: 'C' }, // 'F' for Fahrenheit
|
||||||
|
// units: { temperature: 'F' }
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
// Rendering budget
|
// Rendering budget
|
||||||
@@ -64,14 +74,14 @@ window.CONFIG = {
|
|||||||
// and upscaled with image-rendering: pixelated, so it reads as pixel
|
// 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.
|
// art instead of a blurry rescale. The DOM UI stays crisp at any value.
|
||||||
// 1 = native resolution (sharpest, most expensive).
|
// 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
|
// Scene frame cap. All motion is time-based, so this only changes
|
||||||
// smoothness, never speed. 0 = free running (vsync).
|
// 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
|
// MSAA on the WebGL framebuffer. Costs fill rate, and with renderScale
|
||||||
// below 1 the pixel blocks dominate anyway - set false if the scene is
|
// 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.
|
// GPU bound. Read once at context creation, so a reload is needed.
|
||||||
antialias: true,
|
antialias: true, // false saves GPU fill rate
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
// Location
|
// Location
|
||||||
@@ -82,6 +92,7 @@ window.CONFIG = {
|
|||||||
lat: 48.5667,
|
lat: 48.5667,
|
||||||
lon: 13.4319
|
lon: 13.4319
|
||||||
// label: 'Passau' // overrides the reverse-geocoded name
|
// 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).
|
// false = live Open-Meteo conditions (also used for the theme choice).
|
||||||
// true = cycle sunny -> cloudy -> stormy -> night, useful to compare
|
// true = cycle sunny -> cloudy -> stormy -> night, useful to compare
|
||||||
// all weather looks without waiting on the API.
|
// 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
|
weatherSimInterval: 30000, // ms per weather step when weatherSim is true
|
||||||
|
// weatherSim: true, weatherSimInterval: 15000
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
// Tiles and caches
|
// Tiles and caches
|
||||||
@@ -101,15 +113,17 @@ window.CONFIG = {
|
|||||||
// ('background-tiles' / store 'tiles') and are never re-fetched once
|
// ('background-tiles' / store 'tiles') and are never re-fetched once
|
||||||
// cached: a warm cache renders fully offline.
|
// cached: a warm cache renders fully offline.
|
||||||
tiles: {
|
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
|
debug: false // true = tile borders + N/S + x/y labels baked
|
||||||
// into the ground texture (orientation debug)
|
// into the ground texture (orientation debug)
|
||||||
|
// tiles: { expireDays: 30, debug: true }
|
||||||
},
|
},
|
||||||
ground: {
|
ground: {
|
||||||
// 'satellite' = ESRI World_Imagery (aerial, no labels)
|
// 'satellite' = ESRI World_Imagery (aerial, no labels)
|
||||||
// 'streets' = ESRI World_Street_Map (with place names)
|
// 'streets' = ESRI World_Street_Map (with place names)
|
||||||
// Both are cached separately (cache id prefix 'sat/' vs plain).
|
// Both are cached separately (cache id prefix 'sat/' vs plain).
|
||||||
style: 'satellite'
|
style: 'satellite'
|
||||||
|
// style: 'streets'
|
||||||
},
|
},
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
@@ -121,6 +135,8 @@ window.CONFIG = {
|
|||||||
orbit: {
|
orbit: {
|
||||||
radiusKm: 60, // lobe tip reach (clamped ~190 km so the
|
radiusKm: 60, // lobe tip reach (clamped ~190 km so the
|
||||||
// tips plus the fog dome fit the mosaic)
|
// 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
|
clockwise: true, // travel direction along the eight
|
||||||
reorient: true, // false keeps the bearing across crossings
|
reorient: true, // false keeps the bearing across crossings
|
||||||
// Vertical bobbing inside the 15-35 km band: centre 25 km, amp is
|
// Vertical bobbing inside the 15-35 km band: centre 25 km, amp is
|
||||||
@@ -135,6 +151,8 @@ window.CONFIG = {
|
|||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
fog: {
|
fog: {
|
||||||
distanceKm: 120 // fully saturated haze at this range; 0/false = off
|
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
|
// World units (1 unit ~ 12.9 km). Keep 'top' below the lowest flight
|
||||||
// altitude so aircraft fly above the deck.
|
// altitude so aircraft fly above the deck.
|
||||||
clouds: {
|
clouds: {
|
||||||
enabled: true,
|
enabled: true, // false removes the volumetric cloud deck
|
||||||
top: 1.0, // ~12.9 km
|
top: 1.0, // ~12.9 km
|
||||||
bottom: -0.2, // ~-2.6 km (deck base slightly below terrain)
|
bottom: -0.2, // ~-2.6 km (deck base slightly below terrain)
|
||||||
// Coverage per weather level, 0 = clear, 1 = overcast. Only the
|
// 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
|
// bearing. speedScale exaggerates real advection so the motion is
|
||||||
// visible at the world scale (1 unit ~ 12.9 km).
|
// visible at the world scale (1 unit ~ 12.9 km).
|
||||||
wind: {
|
wind: {
|
||||||
speedScale: 80,
|
speedScale: 80, // 0 = no wind motion, 40 slow, 120 fast
|
||||||
minSpeed: 0.004,
|
minSpeed: 0.004, // world units/s floor when API wind is calm
|
||||||
maxSpeed: 0.08
|
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 }
|
// 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
|
// Paths are Bezier curves resampled to arc length, flown as a full
|
||||||
// profile: climb, cruise, descent, landing, ground hold, new leg.
|
// profile: climb, cruise, descent, landing, ground hold, new leg.
|
||||||
flights: {
|
flights: {
|
||||||
enabled: true,
|
enabled: true, // false removes aircraft and contrails
|
||||||
altitudeKm: 14, // cruise altitude
|
altitudeKm: 14, // cruise altitude
|
||||||
climbKm: 100, // climb/descent run to and from cruise
|
climbKm: 100, // climb/descent run to and from cruise
|
||||||
count: 21, // simultaneous aircraft (max 240)
|
count: 21, // simultaneous aircraft (max 240)
|
||||||
@@ -213,11 +233,12 @@ window.CONFIG = {
|
|||||||
wStrip: 1,
|
wStrip: 1,
|
||||||
// Contrails: contrailChance of the aircraft leaves a trail once
|
// Contrails: contrailChance of the aircraft leaves a trail once
|
||||||
// above contrailStartKm, visible for contrailLifeS seconds.
|
// above contrailStartKm, visible for contrailLifeS seconds.
|
||||||
contrailChance: 1.00,
|
contrailChance: 1.00, // 0 = no contrails, 1 = every eligible jet
|
||||||
contrailStartKm: 4,
|
contrailStartKm: 4, // start after this distance from the airport
|
||||||
contrailLifeS: 300,
|
contrailLifeS: 300, // seconds before a trail disappears
|
||||||
contrailWidthM: 1400, // full trail width
|
contrailWidthM: 1400, // full trail width
|
||||||
contrailFadeKm: 300, // fully faded at this distance (ramp starts at 35 %)
|
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
|
// 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
|
// 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
|
// 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.
|
// height field the terrain shadows are cast against.
|
||||||
terrain: {
|
terrain: {
|
||||||
enabled: true, // false = flat plane (no DEM, no terrain shadows)
|
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)
|
exaggeration: 8, // vertical scale (1 = real, nearly invisible here)
|
||||||
edgeFadeTiles: 4, // soft rim at the mosaic border, in tiles (~13 km)
|
edgeFadeTiles: 4, // soft rim at the mosaic border, in tiles (~13 km)
|
||||||
edgeSkirtKm: 800, // coarse outer terrain pulled past the horizon
|
edgeSkirtKm: 800, // coarse outer terrain pulled past the horizon
|
||||||
edgeSkirtRings: 24, // coarse rings in the outer skirt
|
edgeSkirtRings: 24, // coarse rings in the outer skirt
|
||||||
edgeSkirtNoise: 0.28, // fallback height variation if outer DEM is off
|
edgeSkirtNoise: 0.28, // fallback height variation if outer DEM is off
|
||||||
outerDem: {
|
outerDem: {
|
||||||
enabled: true,
|
enabled: true, // false uses procedural fallback heights
|
||||||
zoom: 7, // reduced-resolution terrarium zoom for the skirt
|
zoom: 7, // reduced-resolution terrarium zoom for the skirt
|
||||||
maxMeters: 2500 // height normalization for skirt colors
|
maxMeters: 2500 // height normalization for skirt colors
|
||||||
|
// outerDem: { enabled: false }
|
||||||
},
|
},
|
||||||
carLights: true, // moving vehicle lights on the real road network
|
carLights: true, // moving vehicle lights on the real road network
|
||||||
cityLights: true, // settlement lights from OSM place nodes
|
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/
|
// Roads come from Overpass (motorway/trunk for the A-net, primary/
|
||||||
// secondary for the side layer), cached per grid cell.
|
// secondary for the side layer), cached per grid cell.
|
||||||
carLights: {
|
carLights: {
|
||||||
|
// All distances are real metres/km unless the name says Px.
|
||||||
roadWidthM: 24, // real carriageway width of the road line
|
roadWidthM: 24, // real carriageway width of the road line
|
||||||
bandPx: 1.2, // pixel floor 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)
|
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.
|
// Japan, Australia, India, southern Africa, ...), 'left'/'right' forces it.
|
||||||
trafficSide: 'auto',
|
trafficSide: 'auto',
|
||||||
dashM: 620, // mean vehicle spacing on motorways
|
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
|
spreadKm: 45, // gaussian sigma around the motorway network
|
||||||
spreadFloor: 0.30, // share that far side roads keep
|
spreadFloor: 0.30, // share that far side roads keep
|
||||||
speed: 1.0, // flow speed multiplier
|
speed: 1.0, // flow speed multiplier
|
||||||
density: 1.0, // vehicle density multiplier
|
density: 1.0, // vehicle density multiplier
|
||||||
brightness: 1.3 // vehicle light intensity
|
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
|
// 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.
|
// is civil twilight. In the morning the same thresholds switch off again.
|
||||||
lights: {
|
lights: {
|
||||||
offDeg: 5,
|
offDeg: 5, // sun altitude where lights start switching off
|
||||||
onDeg: -6,
|
onDeg: -6, // sun altitude where lights are fully on
|
||||||
softDeg: 1.2 // width of the individual transition
|
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)
|
airGain: 0.55, // Rayleigh airlight strength (blue-biased)
|
||||||
physicalSky: true, // Rayleigh sky scattering instead of pure theme gradient
|
physicalSky: true, // Rayleigh sky scattering instead of pure theme gradient
|
||||||
rayleighGain: 8.0, // exposure for the physical sky term
|
rayleighGain: 8.0, // exposure for the physical sky term
|
||||||
distanceFog: false, // legacy aerial perspective is off
|
|
||||||
haze: {
|
haze: {
|
||||||
enabled: false, // full-screen haze pass causes horizon/sky flicker
|
enabled: false, // full-screen haze pass causes horizon/sky flicker
|
||||||
heightKm: 100,
|
heightKm: 100,
|
||||||
@@ -336,12 +363,14 @@ window.CONFIG = {
|
|||||||
maxAlpha: 0.55
|
maxAlpha: 0.55
|
||||||
},
|
},
|
||||||
terrainHaze: {
|
terrainHaze: {
|
||||||
enabled: true,
|
enabled: true, // terrain-distance based haze on the ground
|
||||||
scaleHeightKm: 8.5,
|
scaleHeightKm: 8.5, // exponential vertical falloff
|
||||||
density: 0.22,
|
density: 0.22, // optical depth per world unit
|
||||||
gain: 1.0,
|
gain: 1.0, // overall multiplier
|
||||||
maxAlpha: 0.65,
|
maxAlpha: 0.65, // maximum haze opacity
|
||||||
color: [0.58, 0.64, 0.72]
|
color: [0.58, 0.64, 0.72] // fallback colour; dynamic night tint overrides
|
||||||
|
// terrainHaze: { enabled: false }
|
||||||
|
// terrainHaze: { density: 0.35, maxAlpha: 0.80 }
|
||||||
},
|
},
|
||||||
airHaze: {
|
airHaze: {
|
||||||
enabled: false, // replaced by stable front haze using terrain distance
|
enabled: false, // replaced by stable front haze using terrain distance
|
||||||
@@ -352,27 +381,37 @@ window.CONFIG = {
|
|||||||
color: [0.58, 0.64, 0.72]
|
color: [0.58, 0.64, 0.72]
|
||||||
},
|
},
|
||||||
frontHaze: {
|
frontHaze: {
|
||||||
enabled: true,
|
enabled: true, // stable front haze pass using terrain distance
|
||||||
scaleHeightKm: 8.5,
|
scaleHeightKm: 8.5,
|
||||||
density: 0.22,
|
density: 0.22,
|
||||||
gain: 1.0,
|
gain: 1.0,
|
||||||
maxAlpha: 0.65,
|
maxAlpha: 0.65,
|
||||||
color: [0.58, 0.64, 0.72]
|
color: [0.58, 0.64, 0.72]
|
||||||
|
// frontHaze: { enabled: false }
|
||||||
|
// frontHaze: { density: 0.30, maxAlpha: 0.75 }
|
||||||
},
|
},
|
||||||
model: {
|
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
|
hazeResidual: 0.30, // surface colour surviving at the full fog distance
|
||||||
cloudBrightness: 1.0, // cloud albedo (theme hue, brightness from the model)
|
cloudBrightness: 1.0, // cloud albedo (theme hue, brightness from the model)
|
||||||
cloudHaze: 0.22, // share of the ground haze applied to the deck
|
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.
|
// Cloud shadows: the terrain samples the same cloud field as the sky pass.
|
||||||
cloudShadows: true,
|
cloudShadows: true,
|
||||||
cloudShadowDensity: 1.8, // optical depth through the deck
|
cloudShadowDensity: 1.8, // optical depth through the deck
|
||||||
cloudShadowFloor: 0.06, // darkest shade under a thick cloud
|
cloudShadowFloor: 0.06, // darkest shade under a thick cloud
|
||||||
cloudShadowAmbient: 0.65, // share of the skylight a deck also blocks
|
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.
|
// Terrain self-shadowing over the DEM height field.
|
||||||
terrainShadows: true,
|
terrainShadows: true,
|
||||||
terrainShadowFloor: 0.42, // brightness a fully shadowed slope keeps (0 = black)
|
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):
|
// Optional variants (leave commented out to use the defaults):
|
||||||
// turbidity: 3.0 // hazy, warm, strongly reddened low sun
|
// turbidity: 3.0 // hazy, warm, strongly reddened low sun
|
||||||
// moonGain: 1.2 // bright full-moon nights
|
// moonGain: 1.2 // bright full-moon nights
|
||||||
@@ -388,6 +427,22 @@ window.CONFIG = {
|
|||||||
stars: {
|
stars: {
|
||||||
tint: 0.10, // 0 = pure white points, 1 = full blackbody colour
|
tint: 0.10, // 0 = pure white points, 1 = full blackbody colour
|
||||||
brightness: 1.6 // overall glow of the catalogue points
|
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: {
|
curvature: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
earthRadiusKm: 6371,
|
earthRadiusKm: 6371, // physical Earth radius used for the bend
|
||||||
exaggeration: 4.0
|
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.
|
// Below the horizon the view holds the moon's azimuth at the horizon.
|
||||||
camera: {
|
camera: {
|
||||||
aim: 'off', // 'off' | 'moon'
|
aim: 'off', // 'off' | 'moon'
|
||||||
|
// aim: 'moon' // look at the moon while flying the path
|
||||||
aimEase: 0.94, // 0 = instant turn, 0.99 = very slow
|
aimEase: 0.94, // 0 = instant turn, 0.99 = very slow
|
||||||
aimBob: 0.25 // share of the altitude bob kept while aiming
|
aimBob: 0.25 // share of the altitude bob kept while aiming
|
||||||
// camera: { aim: 'moon' } // look at the moon
|
// camera: { aim: 'moon' } // look at the moon
|
||||||
@@ -435,9 +493,7 @@ window.CONFIG = {
|
|||||||
day: {
|
day: {
|
||||||
startAt: null, // null = strictly real time
|
startAt: null, // null = strictly real time
|
||||||
speed: 1 // virtual seconds per real second
|
speed: 1 // virtual seconds per real second
|
||||||
// day: { startAt: '2026-10-29T20:56', speed: 1 } // start at a chosen
|
// startAt: '2026-10-29T20:56', speed: 1440 // one simulated day per minute
|
||||||
// // moment, real pace
|
|
||||||
// day: { startAt: '2026-10-29T20:56', speed: 1440 } // accelerated
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
|
|||||||
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_AIR_GAIN = (typeof ATMO.airGain === 'number') ? Math.max(0.05, ATMO.airGain) : 0.55;
|
||||||
var ATMO_HAZE_RESIDUAL = (typeof ATMO.hazeResidual === 'number')
|
var ATMO_HAZE_RESIDUAL = (typeof ATMO.hazeResidual === 'number')
|
||||||
? Math.max(0.02, Math.min(0.95, ATMO.hazeResidual)) : 0.30;
|
? 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 ATMO_MODEL = ATMO.model || {};
|
||||||
var HAZE_CFG = ATMO.haze || {};
|
var HAZE_CFG = ATMO.haze || {};
|
||||||
var ATMO_MODEL_ON = (typeof HAZE_CFG.enabled === 'boolean')
|
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
|
// 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
|
// sun-lit white; by night they stay visible as dimmed moonlit streaks
|
||||||
// (reusing the car-lights night ramp), around 40 % strength.
|
// (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 CT2_SEG = 18;
|
||||||
var ct2Buf = null, ct2Vbo = null, ct2Verts = 0;
|
var ct2Buf = null, ct2Vbo = null, ct2Verts = 0;
|
||||||
var ct2Prog = null, ct2A = null, ct2U = null;
|
var ct2Prog = null, ct2A = null, ct2U = null;
|
||||||
@@ -5518,95 +5514,6 @@ var CT2_FRAG_SRC = [
|
|||||||
'}'
|
'}'
|
||||||
].join('\n');
|
].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() {
|
function decodePlaneVerts() {
|
||||||
if (planeV || !window.__planeVerts) return;
|
if (planeV || !window.__planeVerts) return;
|
||||||
try {
|
try {
|
||||||
@@ -5672,6 +5579,12 @@ function planetHeliocentric(p, d) {
|
|||||||
var z = r * Math.sin(u) * Math.sin(i);
|
var z = r * Math.sin(u) * Math.sin(i);
|
||||||
return [x, y, z];
|
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) {
|
function updatePlanetPoints(gl, date) {
|
||||||
if (!gl || !date) return;
|
if (!gl || !date) return;
|
||||||
var d = (date.getTime() - Date.UTC(2000, 0, 1, 12, 0, 0)) / 86400000;
|
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);
|
var ceps = Math.cos(eps), seps = Math.sin(eps);
|
||||||
for (var pi = 0; pi < PLANET_ELEMENTS.length; pi++) {
|
for (var pi = 0; pi < PLANET_ELEMENTS.length; pi++) {
|
||||||
var p = PLANET_ELEMENTS[pi];
|
var p = PLANET_ELEMENTS[pi];
|
||||||
|
if (!PLANETS_ON) continue;
|
||||||
|
if (!PLANET_SHOW_PLUTO && p.name === 'Pluto') continue;
|
||||||
var helio = planetHeliocentric(p, d);
|
var helio = planetHeliocentric(p, d);
|
||||||
var gx = helio[0] - earth[0];
|
var gx = helio[0] - earth[0];
|
||||||
var gy = helio[1] - earth[1];
|
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 = mag + 5 * Math.log10(Math.max(1e-6, rGeo * rSun));
|
||||||
mag = Math.max(-5.0, Math.min(16.0, mag));
|
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)));
|
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++] = p.color[0]; data[di++] = p.color[1]; data[di++] = p.color[2];
|
||||||
data[di++] = bright;
|
data[di++] = bright * PLANET_BRIGHT;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
if (!planetVbo) planetVbo = gl.createBuffer();
|
if (!planetVbo) planetVbo = gl.createBuffer();
|
||||||
|
|||||||
Reference in new issue
Block a user