One commited on
Commit
5f99515
·
verified ·
1 Parent(s): cc89a7c

Upload index.html

Browse files
Files changed (1) hide show
  1. index.html +37 -20
index.html CHANGED
@@ -119,9 +119,8 @@ function frac(v){ return v - Math.floor(v); }
119
  // on is the ground it is drawn on to within about a millionth of a metre.
120
  const F32 = v => Math.fround(v);
121
  function lhash(x, z){ return (ihash((Math.imul(x, 3419) + Math.imul(z, 2147483647)) >>> 0) & 1023) / 1023; }
122
- function lnoise(x, z){
123
- const px = F32(x*0.08), pz = F32(z*0.08);
124
- const ix = Math.floor(px), iz = Math.floor(pz), fx = px - ix, fz = pz - iz;
125
  const sx = fx*fx*(3 - 2*fx), sz = fz*fz*(3 - 2*fz);
126
  const a = lhash(ix, iz), b = lhash(ix+1, iz), c = lhash(ix, iz+1), d = lhash(ix+1, iz+1);
127
  const u = a + (b-a)*sx, v = c + (d-c)*sx;
@@ -143,10 +142,12 @@ function islandAt(cx, cz){
143
  else if(low >= 96) return null; // most of the world is open sea
144
  const s = ihash(h) & 0xFFFFFF;
145
  const rb = s & 63, pk = (s >> 6) & 15, sh = (s >> 10) & 15, rg = (s >> 14) & 15;
146
- const r = type === 1 ? 50 + rb*0.31 : type === 2 ? 9 + rb*0.14 : 14 + rb*0.25;
147
  return {
148
- x: (cx + 0.5 + ((h >>> 8 & 255) - 127.5)/256) * ICELL,
149
- z: (cz + 0.5 + ((h >>> 16 & 255) - 127.5)/256) * ICELL,
 
 
150
  r, code: pk + sh*16 + rg*256 + type*4096
151
  };
152
  }
@@ -158,7 +159,7 @@ function decode(code){
158
  // straight fall over the last fraction of it, which is the beach the boat can actually sit on.
159
  if(type === 1){ peak = 2.0 + pk*0.35; ramp = 0.10 + sh*0.04; }
160
  else if(type === 2){ peak = 14.0 + pk*1.6; shape = 0.04 + sh*0.012; }
161
- return { peak, shape, rough: rg/15, type, ramp };
162
  }
163
 
164
  function landH(x, z){
@@ -172,11 +173,23 @@ function landH(x, z){
172
  for(let j=-span;j<=span;j++) for(let i=-span;i<=span;i++){
173
  const isl = islandAt(cx+i, cz+j);
174
  if(!isl) continue;
175
- const d = Math.hypot(x - isl.x, z - isl.z);
176
- if(d > isl.r) continue;
177
  const p = decode(isl.code);
178
- const k = 1 - d/isl.r; // monotone: downhill always leads back to the sea
179
- const nz = 0.55 + 0.45*p.rough*lnoise(x, z);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  const terr = (p.ramp > 0 ? Math.min(1, k/p.ramp) : Math.pow(k, p.shape)) * nz;
181
  h = Math.max(h, p.peak*terr - LAND.shelf); // the shelf is the shallow ring around an island
182
  }
@@ -218,15 +231,14 @@ float fbm(vec2 p, int oct){
218
  `;
219
 
220
  const ISLANDS_GLSL = `
221
- uniform vec4 uIsl[25];
222
  uniform int uCount;
223
  uint ihash(uint n){
224
  n ^= n >> 15; n *= 0x2c1b3c9du; n ^= n >> 12; n *= 0x297a2d39u; n ^= n >> 15;
225
  return n;
226
  }
227
  float lhash(int x, int y){ return float(ihash(uint(x)*3419u + uint(y)*2147483647u) & 1023u) / 1023.0; }
228
- float lnoise(vec2 p){
229
- p = p * 0.08; // same lattice scale as the JS copy
230
  ivec2 i = ivec2(floor(p));
231
  vec2 f = p - vec2(float(i.x), float(i.y));
232
  f = f*f*(3.0-2.0*f);
@@ -237,18 +249,23 @@ float landH(vec2 p){
237
  float h = -6.0; // no land in range: open water, deep enough that depth reads as deep
238
  for(int i=0;i<uCount;i++){
239
  vec4 isl = uIsl[i];
240
- float d = length(p - isl.xy);
241
- if(d > isl.z) continue;
242
  float code = isl.w;
243
  float pk = mod(code, 16.0), sh = floor(mod(code/16.0, 16.0)), rg = floor(mod(code/256.0, 16.0));
244
  float type = floor(code/4096.0);
245
- float peak = 1.2 + pk*0.22, shape = 1.2 + sh*0.03;
 
 
 
 
 
246
  if(type == 1.0){ peak = 2.0 + pk*0.35; }
247
  else if(type == 2.0){ peak = 14.0 + pk*1.6; shape = 0.04 + sh*0.012; }
248
  float rough = rg/15.0;
249
- float k = 1.0 - d/isl.z;
250
- float nz = 0.55 + 0.45*rough*lnoise(p);
251
- float terr = (type == 1.0) ? min(1.0, k/(0.10 + sh*0.04)) * nz : pow(k, shape) * nz;
252
  h = max(h, peak*terr - 1.2);
253
  }
254
  return h;
 
119
  // on is the ground it is drawn on to within about a millionth of a metre.
120
  const F32 = v => Math.fround(v);
121
  function lhash(x, z){ return (ihash((Math.imul(x, 3419) + Math.imul(z, 2147483647)) >>> 0) & 1023) / 1023; }
122
+ function lnoise(px, pz){ // takes lattice coordinates, so the caller sets the scale
123
+ const ix = Math.floor(px), iz = Math.floor(pz), fx = px-ix, fz = pz-iz;
 
124
  const sx = fx*fx*(3 - 2*fx), sz = fz*fz*(3 - 2*fz);
125
  const a = lhash(ix, iz), b = lhash(ix+1, iz), c = lhash(ix, iz+1), d = lhash(ix+1, iz+1);
126
  const u = a + (b-a)*sx, v = c + (d-c)*sx;
 
142
  else if(low >= 96) return null; // most of the world is open sea
143
  const s = ihash(h) & 0xFFFFFF;
144
  const rb = s & 63, pk = (s >> 6) & 15, sh = (s >> 10) & 15, rg = (s >> 14) & 15;
145
+ const r = F32(type === 1 ? 50 + rb*0.31 : type === 2 ? 9 + rb*0.14 : 14 + rb*0.25);
146
  return {
147
+ // x, z and r are stored as float32 values because that is what the shader receives. Otherwise
148
+ // the two sides can land on different lattice cells and disagree about the island's shape.
149
+ x: F32((cx + 0.5 + ((h >>> 8 & 255) - 127.5)/256) * ICELL),
150
+ z: F32((cz + 0.5 + ((h >>> 16 & 255) - 127.5)/256) * ICELL),
151
  r, code: pk + sh*16 + rg*256 + type*4096
152
  };
153
  }
 
159
  // straight fall over the last fraction of it, which is the beach the boat can actually sit on.
160
  if(type === 1){ peak = 2.0 + pk*0.35; ramp = 0.10 + sh*0.04; }
161
  else if(type === 2){ peak = 14.0 + pk*1.6; shape = 0.04 + sh*0.012; }
162
+ return { peak, shape, rough: F32(rg/15), type, ramp, pk, sh, rg };
163
  }
164
 
165
  function landH(x, z){
 
173
  for(let j=-span;j<=span;j++) for(let i=-span;i<=span;i++){
174
  const isl = islandAt(cx+i, cz+j);
175
  if(!isl) continue;
 
 
176
  const p = decode(isl.code);
177
+ // Nothing here is a circle. Two noise lattices are sized to the island itself: one gives the
178
+ // outline its lobes, the other the surface its hollows and peaks. Both are sampled relative to
179
+ // the island centre so the lattice coordinates stay small, every step is rounded to float32,
180
+ // and the offsets are small integers - otherwise the two sides pick different lattice cells and
181
+ // disagree about the shape, which is what would put the boat on a different height than the
182
+ // ground it is being drawn on.
183
+ const gx = F32(x), gz = F32(z);
184
+ const f1 = F32(F32(2 + Math.floor(p.rg/4)) / isl.r);
185
+ const f2 = F32(F32(6 + p.rg) / isl.r);
186
+ const dx = F32(gx - isl.x), dz = F32(gz - isl.z);
187
+ const d = F32(Math.sqrt(F32(F32(dx)*F32(dx)) + F32(F32(dz)*F32(dz)))); // what length() does in the shader
188
+ const wob = lnoise(F32(F32(dx*f1) + F32(p.pk)), F32(F32(dz*f1) + F32(p.sh)));
189
+ const rr = F32(isl.r * F32(F32(0.55) + F32(F32(0.45)*F32(wob))));
190
+ if(d > rr) continue;
191
+ const k = F32(F32(1.0) - F32(F32(d)/F32(rr)));
192
+ const nz = F32(F32(0.55) + F32(F32(0.45)*F32(p.rough)*lnoise(F32(F32(dx*f2) + F32((p.pk+p.sh+1)%16)), F32(F32(dz*f2) + F32((p.pk+p.sh+7)%16)))));
193
  const terr = (p.ramp > 0 ? Math.min(1, k/p.ramp) : Math.pow(k, p.shape)) * nz;
194
  h = Math.max(h, p.peak*terr - LAND.shelf); // the shelf is the shallow ring around an island
195
  }
 
231
  `;
232
 
233
  const ISLANDS_GLSL = `
234
+ uniform vec4 uIsl[48]; // must match MAX_ISLANDS, otherwise islands past 25 are silently dropped
235
  uniform int uCount;
236
  uint ihash(uint n){
237
  n ^= n >> 15; n *= 0x2c1b3c9du; n ^= n >> 12; n *= 0x297a2d39u; n ^= n >> 15;
238
  return n;
239
  }
240
  float lhash(int x, int y){ return float(ihash(uint(x)*3419u + uint(y)*2147483647u) & 1023u) / 1023.0; }
241
+ float lnoise(vec2 p){ // takes lattice coordinates, so the caller sets the scale
 
242
  ivec2 i = ivec2(floor(p));
243
  vec2 f = p - vec2(float(i.x), float(i.y));
244
  f = f*f*(3.0-2.0*f);
 
249
  float h = -6.0; // no land in range: open water, deep enough that depth reads as deep
250
  for(int i=0;i<uCount;i++){
251
  vec4 isl = uIsl[i];
252
+ vec2 r = p - isl.xy; // island-relative, exactly like the JS copy
253
+ float d = length(r);
254
  float code = isl.w;
255
  float pk = mod(code, 16.0), sh = floor(mod(code/16.0, 16.0)), rg = floor(mod(code/256.0, 16.0));
256
  float type = floor(code/4096.0);
257
+ float f1 = (2.0 + floor(rg/4.0)) / isl.z;
258
+ float f2 = (6.0 + rg) / isl.z;
259
+ float wob = lnoise(r*f1 + vec2(pk, sh));
260
+ float rr = isl.z * (0.55 + 0.45*wob);
261
+ if(d > rr) continue;
262
+ float peak = 1.2 + pk*0.22, shape = 1.2 + sh*0.03, ramp = 0.0;
263
  if(type == 1.0){ peak = 2.0 + pk*0.35; }
264
  else if(type == 2.0){ peak = 14.0 + pk*1.6; shape = 0.04 + sh*0.012; }
265
  float rough = rg/15.0;
266
+ float k = 1.0 - d/rr;
267
+ float nz = 0.55 + 0.45*rough*lnoise(r*f2 + vec2(mod(pk+sh+1.0, 16.0), mod(pk+sh+7.0, 16.0)));
268
+ float terr = (ramp > 0.0) ? min(1.0, k/ramp) * nz : pow(k, shape) * nz;
269
  h = max(h, peak*terr - 1.2);
270
  }
271
  return h;