HOW WANDER IS BUILT · LAYER 5 OF 7

A mesh is a view

Camera, frustum and the one shader.

1. A number is a column2. A column is a height3. A window is a chunk4. A chunk is a mesh5. A mesh is a view6. A world has people7. A world has rules

Wander draws with one terrain shader, one sky shader and one sprite shader, and no textures on the ground. The camera is a perspective matrix and a view matrix from the walker's position, yaw and pitch. Every chunk has a bounding box; six planes from the projection-view matrix cull the boxes that are out of view, and the rest are drawn nearest first. The terrain shader does the weather: the sun's direction and strength, an ambient term, up to four lamps (headlights, street lights, fireballs), a sway on leaves and reeds that grows with the wind, the season's leaf colour, snow above the snow line, cloud shadows drifting from a little value noise, a wet sheen, fog by distance and an aerial haze that pales the far ridges toward the sky. Water is a moving triangle wave in the vertex colour. Emissive faces ignore the sun. The sky is a gradient with the horizon lifted by the pitch, and stars hashed from the pixel at night.

The twenty lines that make it

const gl = canvas.getContext("webgl"), G = WanderGL;    // gl.js: the WebGL client
const proj = G.perspective(new Float32Array(16), 70*Math.PI/180, canvas.width/canvas.height, 0.1, 3000);
const view = G.view(new Float32Array(16), cam.x, cam.y, cam.z, cam.yaw, cam.pitch);
const planes = G.frustumPlanes(G.mul(new Float32Array(16), proj, view));
for (const mesh of meshes){                             // one uploaded mesh per chunk part, with its bounds
  if (!G.boxVisible(planes, mesh.bounds)) continue;     // six plane tests against the corner furthest along each normal
  gl.useProgram(terrain); gl.uniformMatrix4fv(uProj, false, proj); gl.uniformMatrix4fv(uView, false, view);
  gl.uniform3f(uSun, sun.x, sun.y, sun.z); gl.uniform1f(uSunStrength, sun.strength); gl.uniform1f(uWind, wx.wind); gl.uniform1f(uCloud, wx.cloud);
  gl.bindBuffer(gl.ARRAY_BUFFER, mesh.vbo); /* aPos, aNor, aCol, aFlag at stride 40 */ gl.drawElements(gl.TRIANGLES, mesh.count, gl.UNSIGNED_SHORT, 0);
}
// the weather's numbers come from the almanac: wx = WanderLaw.weatherAt(hour), three bits on their own exact clocks

The shaders are in wander/gl.js, in full; the sky, the sun's path and the almanac are the RangeBlends pages' own (bank.js, law.js). The weather clock is on cards/clocks.md.

← A chunk is a mesh A world has people →

How Wander is built · by Lars Rocha · every layer stands on a law in sitoolz, written twice and checked against one fixture.