fps
Use device orientation, mouse, qwe-keys to navigate.
Fractal + spline based procedural world (~20kb in public domain). 3D WebGL model. 60 fps on Nexus 10. Sorry the script uses OES_element_index_uint extension and doesn't work on Mali 400 or Tegra 4.
The World with antialiasing is more smooth, but too heavy for mobile yet.

# Spline based and Fractal terrains

## Tensor product subdivision spline patches

Tensor product of cubic subdivision spline curves is used to make 2D spline patches (random splined terrains). At first an array hi, j of random heights (control points) is generated on regular square grid (see below). Then subdivision and averaging steps are used repeatedly.
 | | | —   hi, j   — hi+½, j —   hi+1, j   — | | | —   hi, j+½   — hi+½, j+½ —   hi+1, j+½   — | | | —   hi, j+1   — hi+½, j+1 —   hi+1, j+1   — | | |
Subdivision step for every old (hi, j , hi+1, j , hi, j+1 , hi+1, j+1 ) quad:
hi+½, j = (hi, j + hi+1, j )/2,
hi, j+½ = (hi, j + hi, j+1 )/2,
hi+½, j+½ = (hi, j + hi+1, j + hi, j+1 + hi+1, j+1 )/4.

Averaging step for all sites of the new lattice:
hi+½, j+½ = (4 hi+½, j+½ + 2 (hi+½, j + hi+½, j+1 + hi, j+½ + hi+1, j+½ ) +
hi, j + hi, j+1 + hi, j+½ + hi+1, j+½ ) / 16.

See Spline based terrain. Procedural 2D smooth noise texture. Compare it with the procedural Fractal texture.

The codes are small enough

``` var k = 512,  m = 32,  c16 = 1/16;
var h = new Float32Array(k*k), hb = new Float32Array(k*k);
var mm = m*m, mm1 = mm - 1,  m1 = m - 1;
for(var i = 0; i < mm; i++ ) h[i] = z0*rand();
while(m < k){
for(var j = 0; j < mm; j += m ){  //  subdivision
var jp = (j + m) & mm1;
for(var i = 0; i < m; i++ ){
var ip = (i + 1) & m1;
var t = i+j,  m2 = m + m;
var h0 = h[t], h1 = h[ip+j], h2 = h[i+jp];
t = 2*(i + 2*j);
hb[t] = h0;
hb[t + m2 + 1] = (h0 + h1 + h2 + h[ip+jp])*.25;
hb[t + 1] = (h0 + h1)*.5;
hb[t + m2] = (h0 + h2)*.5;}}
m = m2;
mm = m*m;  mm1 = mm - 1;  m1 = m - 1;
for(var j = 0; j < mm; j += m ){  // averaging
var jp = (j + m) & mm1,  jm = (j + mm - m) & mm1;
for(var i = 0; i < m; i++ ){
var ip = (i + 1) & m1,  im = (i + m - 1) & m1,  t = i + j;
h[t] = c16*(4*hb[t] +
2*(hb[ip + j] + hb[im + j] + hb[i + jp] + hb[i + jm]) +
hb[ip + jp] + hb[ip + jm] + hb[im + jp] + hb[im + jm]);}}
}
```

## Fractal terrains

To get random multi-scale noise (see Fractal terrains) by the diamond square algorithm we use random disturbation (instead of avereging) of the new points in every subdivision step as
hi+½, j = (hi, j + hi+1, j )/2 + a Random(),
hi, j+½ = (hi, j + hi, j+1 )/2 + a Random(),
hi+½, j+½ = (hi, j + hi+1, j + hi, j+1 + hi+1, j+1 )/4 + a Random()
a = a / 2.

Therefore we can combine random disturbation and smoothing to get complex random procedural mixed terrains (see also 2048×2048 world at the top of the page). "Red planet". Lake with 1250 procedural plants, lake with complex plants and lake editor.

## Terrain editor

A simple Terrain editor.
Contents     updated 26 Aug 2014