mapspinner 0.1.62 → 0.1.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/gl-render.js +1 -1
- package/src/shaders/terrain.glsl +34 -12
package/package.json
CHANGED
package/src/gl-render.js
CHANGED
|
@@ -1051,7 +1051,7 @@ export async function initMapspinnerRender(gl, opts = {}) {
|
|
|
1051
1051
|
gl.uniform1f(U('oceanAmp'), (oc.oceanAmplitude != null) ? oc.oceanAmplitude : 1.0);
|
|
1052
1052
|
gl.uniform1f(U('oceanChoppy'), (oc.oceanChoppiness != null) ? oc.oceanChoppiness : 0.5);
|
|
1053
1053
|
gl.uniform1f(U('oceanFoam'), (oc.oceanFoam != null) ? oc.oceanFoam : 0.5);
|
|
1054
|
-
gl.uniform1f(U('uBeachTopM'), _g('beachTop',
|
|
1054
|
+
gl.uniform1f(U('uBeachTopM'), _g('beachTop', 80.0)); // beach ceiling: grass stops, sand to the waterline + under it. 30->90 (user 2026-06-14: 3x beach width)
|
|
1055
1055
|
|
|
1056
1056
|
// SINGLE INSTANCED DRAW: the deform params that were per-quad uniforms (ox,oy,l,level + face)
|
|
1057
1057
|
// are now PER-INSTANCE attributes. Build one interleaved instance buffer [ox,oy,l,level,face]
|
package/src/shaders/terrain.glsl
CHANGED
|
@@ -1395,6 +1395,7 @@ float canyonMask(vec3 worldPos, float h, float temp, float humid, float px, out
|
|
|
1395
1395
|
#endif // biomeClassColor/riverMask/canyonMask: DEBUGVIEW-only (called solely from displayMode blocks) -- excluded from render FS cold-compile (FS-2, workflow w4y1bnrqc)
|
|
1396
1396
|
|
|
1397
1397
|
vec3 terrainAlbedoClimate(float h, float slope, float rockSlope, float temp, float humid, highp vec3 worldPos, float pxWorld) { // highp: worldPos feeds normalize(worldPos)*freq noise UVs (mottle/river/canyon ridge) -- mediump scrambles the lattice up close
|
|
1398
|
+
highp vec3 nwp = normalize(worldPos); // hoisted: reused by the mottle + river/canyon ridge dirs (was recomputed)
|
|
1398
1399
|
vec3 c = terrainAlbedo(h, slope, rockSlope, worldPos, pxWorld);
|
|
1399
1400
|
if (h < 0.0) {
|
|
1400
1401
|
// SEA ICE: near-polar ocean (very cold) freezes to white-blue pack ice. Pure fn of the
|
|
@@ -1409,7 +1410,13 @@ vec3 terrainAlbedoClimate(float h, float slope, float rockSlope, float temp, flo
|
|
|
1409
1410
|
// vegetation dropped out a beat BEFORE the rock arrived -> a light bare-grass ring. Key veg off the
|
|
1410
1411
|
// SAME rockSlope so vegetation fades EXACTLY as rock fades in -> grass stays dark right up to the
|
|
1411
1412
|
// rock with no light gap, and veg is 0 wherever rock is full (no biome-green bleeding onto rock).
|
|
1412
|
-
|
|
1413
|
+
// BREAK THE VEG RING (user 2026-06-14 'hard separation between dark and light grass, a hard circle
|
|
1414
|
+
// around mountains'): veg dropped at a clean elevation+slope threshold -> a dark->light grass ring
|
|
1415
|
+
// circling every peak. Warp BOTH thresholds with ONE cheap noise (~2-3km) so the dark/light grass
|
|
1416
|
+
// boundary fingers irregularly instead of a contour ring. (Reuses the hoisted nwp; one snoise3.)
|
|
1417
|
+
float vegN = snoise3(nwp * 2400.0);
|
|
1418
|
+
float veg = (1.0 - smoothstep(bandEdgesHi.x + vegN * 850.0, bandEdgesHi.y + vegN * 850.0, h))
|
|
1419
|
+
* (1.0 - smoothstep(slopeRock.x, slopeRock.y + vegN * 0.13, rockSlope));
|
|
1413
1420
|
// ELEVATION + LATITUDE BIOME BIAS (user 2026-06-02: 'the hypsometric ramp should influence biome
|
|
1414
1421
|
// distribution, pulling biomes out of their anchor areas a bit for better distribution'). On top
|
|
1415
1422
|
// of the anchor climate temp/humid, bias the EFFECTIVE temperature DOWN with elevation (lapse rate
|
|
@@ -1430,7 +1437,7 @@ vec3 terrainAlbedoClimate(float h, float slope, float rockSlope, float temp, flo
|
|
|
1430
1437
|
// soil/moisture/vegetation patchiness mottles albedo. Reuse the snoise3 already evaluated for
|
|
1431
1438
|
// cliffRock (same normalize(worldPos)*~1k pattern, no new octave) as a VALUE-only multiplier (NO
|
|
1432
1439
|
// hue jitter, low 1200 freq -> does NOT reintroduce the per-pixel swamp moire the pipeline removed).
|
|
1433
|
-
float mot = snoise3(
|
|
1440
|
+
float mot = snoise3(nwp * 120.0); // detail-tex-rockface-canyon-10x: *1200->*120 (~10x larger mottle features, user 2026-06-06)
|
|
1434
1441
|
c *= (1.0 + uVariationAmt * mot);
|
|
1435
1442
|
// earlier snow/ice on high ground in cold regions.
|
|
1436
1443
|
float coldSnow = (1.0 - smoothstep(0.30, 0.75, temp)) * smoothstep(snowEdges.x * 0.5, snowEdges.x, h);
|
|
@@ -1480,7 +1487,7 @@ vec3 terrainAlbedoClimate(float h, float slope, float rockSlope, float temp, flo
|
|
|
1480
1487
|
// the deleted 2026-06-01 detail texturing), value-only (no hue shift), and each octave fades out
|
|
1481
1488
|
// via a pxWorld Nyquist gate before its features go sub-pixel (no orbit speckle, no leopard band).
|
|
1482
1489
|
{
|
|
1483
|
-
highp vec3 od =
|
|
1490
|
+
highp vec3 od = nwp;
|
|
1484
1491
|
float ov = 0.0, oa = 0.0;
|
|
1485
1492
|
float fq = 75.0, am = 1.0; // octaves: ~84km / 17km / 3.4km features (halved to match VS detailFbm)
|
|
1486
1493
|
int fdOcts = (uFSDetailOcts > 0) ? uFSDetailOcts : 3;
|
|
@@ -1538,7 +1545,8 @@ void main() {
|
|
|
1538
1545
|
// PER-FRAGMENT tangent frame from vWorld (the sphere position, C0 across quad edges):
|
|
1539
1546
|
// uz = up (radial), ux = normalize(Y x uz), uy = uz x ux. Continuous across adjacent quads
|
|
1540
1547
|
// -> no per-quad shading-baseline seam.
|
|
1541
|
-
vec3
|
|
1548
|
+
highp vec3 nWorld = normalize(vWorld); // computed ONCE, reused for the tangent up + every band/noise/lighting dir (perf: was ~7 separate normalize() calls)
|
|
1549
|
+
vec3 uz = nWorld;
|
|
1542
1550
|
// AUDIT FIX 2026-06-06 (audit-tangent-frame-degeneracy): the reference axis was a FIXED vec3(0,1,0),
|
|
1543
1551
|
// so cross(Y, uz) -> zero-length (NaN normal) wherever uz is parallel to Y -- i.e. the +Y/-Y cube
|
|
1544
1552
|
// faces and the poles, exactly 'wrong normals in the wrong places'. Pick the world axis LEAST
|
|
@@ -1787,7 +1795,7 @@ void main() {
|
|
|
1787
1795
|
// SHARED biome-band warp pattern (user 2026-06-14: the SAME warping on snow/rock bands AND the
|
|
1788
1796
|
// beach->land crossover). 2-oct world-dir noise, 1/4 freq (~13km + ~5km waves). Computed once
|
|
1789
1797
|
// here; the snow/rock bandWarp below reuses warpN. highp dir for the lattice precision.
|
|
1790
|
-
highp vec3 bwDir =
|
|
1798
|
+
highp vec3 bwDir = nWorld;
|
|
1791
1799
|
// 3-oct (added the ~1km octave, user 2026-06-14 'make biome bands more interesting') -> the
|
|
1792
1800
|
// texture-splat rock/snow/beach edges break into finer fingers as you approach, not a hard band.
|
|
1793
1801
|
float warpN = snoise3(bwDir * 3325.0) + 0.5 * snoise3(bwDir * 7750.0) + 0.35 * snoise3(bwDir * 17000.0); // ~ +/-1.8
|
|
@@ -1884,14 +1892,22 @@ void main() {
|
|
|
1884
1892
|
// off (= the old low-freq look) -- no second octave, no detailFade. Albedo = luma STRUCTURE (macro
|
|
1885
1893
|
// color carries chroma); normal strong (x1.4); displacement drives the height-blend (mips soften
|
|
1886
1894
|
// the displacement, and thus the blend, at distance automatically).
|
|
1895
|
+
// LOW-OCTAVE NORMAL BLEND (user 2026-06-14 'blend the higher octave with the lower octave's
|
|
1896
|
+
// NORMALS for a less repetitive faraway look -- dont fade it, draw both'): the high octave (wt4)
|
|
1897
|
+
// tiles tightly so it repeats visibly far off; ADD the low octave (wt, 2.4km, less repetitive)
|
|
1898
|
+
// NORMAL on top -- ALWAYS, no fade -- to break that repetition. Albedo stays high-octave only.
|
|
1887
1899
|
highp vec3 wt4 = wt * 4.0;
|
|
1888
1900
|
vec4 albA = surfTriTap(uSurfAlb, wt4, tw, lA);
|
|
1889
|
-
vec3 cA = vec3(dot(albA.rgb, LUMA));
|
|
1901
|
+
vec3 cA = vec3(dot(albA.rgb, LUMA));
|
|
1902
|
+
vec3 nA = surfTriNrm(uSurfNrm, wt4, tw, lA, n) * 1.4 + surfTriNrm(uSurfNrm, wt, tw, lA, n) * 0.8; // high + low-octave normal
|
|
1903
|
+
float dispA = albA.a;
|
|
1890
1904
|
vec4 texAlb = vec4(cA, dispA); vec3 texNrm = nA;
|
|
1891
1905
|
float splatRock = (abs(lA - 1.0) < 0.5) ? 1.0 : 0.0; // height-blend rock fraction (layer 1 = rock)
|
|
1892
1906
|
if (wB > 0.02) { // second layer only where a real transition exists
|
|
1893
1907
|
vec4 albB = surfTriTap(uSurfAlb, wt4, tw, lB);
|
|
1894
|
-
vec3 cB = vec3(dot(albB.rgb, LUMA));
|
|
1908
|
+
vec3 cB = vec3(dot(albB.rgb, LUMA));
|
|
1909
|
+
vec3 nB = surfTriNrm(uSurfNrm, wt4, tw, lB, n) * 1.4 + surfTriNrm(uSurfNrm, wt, tw, lB, n) * 0.8; // high + low-octave normal
|
|
1910
|
+
float dispB = albB.a;
|
|
1895
1911
|
// HEIGHT-BLEND POKE-THROUGH (user 'each texture's higher areas should poke through the other,
|
|
1896
1912
|
// offset by the ramp'): height = displacement + a weight-ramp offset (gate positions the
|
|
1897
1913
|
// boundary); higher wins over a soft width so the loser's high bumps poke through = fingers,
|
|
@@ -1944,6 +1960,12 @@ void main() {
|
|
|
1944
1960
|
// grey). The 4x detail carries the fine structure for every material.
|
|
1945
1961
|
vec3 texIdent = texC * (albedo / max(texL, 0.02));
|
|
1946
1962
|
albedo = clamp(mix(albedo, mix(detail, texIdent, photoF), k), 0.0, 1.0);
|
|
1963
|
+
// FAKE MIDDAY AO from the displacement (user 2026-06-14 'darken the deepest parts of the
|
|
1964
|
+
// displacement textures a little'): the texture's LOWEST displacement = crevices/pits; darken
|
|
1965
|
+
// them ~18% so the surface reads as sunlit-from-above with soft self-occlusion in the lows.
|
|
1966
|
+
// Faded by k so the far field (where the texture mips out) is untouched.
|
|
1967
|
+
float texAO = mix(1.0, mix(0.82, 1.0, smoothstep(0.0, 0.5, texAlb.a)), k);
|
|
1968
|
+
albedo *= texAO;
|
|
1947
1969
|
// displacement-normal relief: WORLD-SPACE UDN perturbation from surfTriNrm (each projection
|
|
1948
1970
|
// plane's tangent axes, not the radial frame). Amplitude capped low (scramble lesson d262b5e);
|
|
1949
1971
|
// applied AFTER the uReliefShade exaggeration below so the exaggeration never amplifies it.
|
|
@@ -2204,11 +2226,11 @@ void main() {
|
|
|
2204
2226
|
// peak at the terminator (N.sun~0), fall off toward both day-center and night-center, and
|
|
2205
2227
|
// SQUARE it so the warm band is tight at the day/night line instead of a fat ring round the
|
|
2206
2228
|
// whole limb. Warm amber (not pure red) so it reads as sunset haze, not a bruise.
|
|
2207
|
-
float gz = 1.0 - abs(dot(
|
|
2229
|
+
float gz = 1.0 - abs(dot(nWorld, sunDir));
|
|
2208
2230
|
float graze = smoothstep(0.55, 1.0, gz); graze *= graze;
|
|
2209
2231
|
// only on the LIT side of the terminator (mu>0) -- past the line the surface is night and
|
|
2210
2232
|
// additive amber on near-black extinct land reads as a scorched maroon rim. Day-gate kills it.
|
|
2211
|
-
float termDay = smoothstep(-0.02, 0.18, dot(
|
|
2233
|
+
float termDay = smoothstep(-0.02, 0.18, dot(nWorld, sunDir));
|
|
2212
2234
|
hazed += uTerminatorGlow * graze * termDay * vec3(1.0, 0.55, 0.34) * apGate;
|
|
2213
2235
|
color = mix(lit, hazed, apGate * uHazeMul); // uHazeMul lever (2026-06-10 'pale hazy': full-strength haze milked the midground)
|
|
2214
2236
|
}
|
|
@@ -2238,7 +2260,7 @@ void main() {
|
|
|
2238
2260
|
// SEABED LIGHTING (user 'floor too flat/dim'): the deep floor gets almost no direct sun, so it
|
|
2239
2261
|
// read dim+flat. Lift the brightness and add an up-facing fill (brighter where the surface faces
|
|
2240
2262
|
// up, darker on slopes -> 3D relief) + a touch of slope contrast keyed on the lit normal vNrm.
|
|
2241
|
-
float upFill = mix(0.75, 1.35, clamp(dot(vNrm,
|
|
2263
|
+
float upFill = mix(0.75, 1.35, clamp(dot(vNrm, nWorld) * 0.5 + 0.5, 0.0, 1.0));
|
|
2242
2264
|
color *= upFill * 1.5;
|
|
2243
2265
|
color = mix(color * uwTrans + uwFog * (1.0 - uwTrans), uwFog, smoothstep(100000.0, 500000.0, dKm * 1000.0));
|
|
2244
2266
|
}
|
|
@@ -2306,7 +2328,7 @@ void main() {
|
|
|
2306
2328
|
// SPHERE sun angle to EVERY fragment (land + ocean) so the globe reads 3D: bright at the sub-solar
|
|
2307
2329
|
// point, falling to dark across the day side into the terminator. dayShade = smoothstep over the
|
|
2308
2330
|
// surface-normal . sun, with a small ambient floor (0.10) so the night/terminator isn't pure black.
|
|
2309
|
-
float macroMu = dot(
|
|
2331
|
+
float macroMu = dot(nWorld, sunDir);
|
|
2310
2332
|
// SOFT FLOORED TERMINATOR (Real-World Look): a wider, smoother twilight band (uTermWidth) with a
|
|
2311
2333
|
// night floor (uNightFloor) so framed night longitudes keep faint detail instead of crushing to
|
|
2312
2334
|
// black (defect #4). The old hard 0.10..-0.12,0.55 band was too steep + too dark.
|
|
@@ -2315,7 +2337,7 @@ void main() {
|
|
|
2315
2337
|
// rounded 3D form instead of a flat disc. viewGraze = surface-normal . view-dir, ->1 facing the
|
|
2316
2338
|
// camera (disc centre), ->0 at the limb. Only bites near the limb so it does not dim the main face.
|
|
2317
2339
|
vec3 viewDir = normalize(camWorld - vWorld);
|
|
2318
|
-
float viewGraze = max(dot(
|
|
2340
|
+
float viewGraze = max(dot(nWorld, viewDir), 0.0);
|
|
2319
2341
|
float limb = 0.45 + 0.55 * smoothstep(0.0, 0.45, viewGraze); // 0.45 at the limb -> 1.0 facing camera
|
|
2320
2342
|
// NIGHT / SHADOW FILL (user 2026-06-09: 'we want night lights in the SHADOW areas, not city lights'):
|
|
2321
2343
|
// a UNIFORM dim fill that lifts the unlit hemisphere out of pure black -- a cool ambient night light,
|