Terrain
Ground is the largest thing most 3D scenes draw and the thing a mesh is worst at: too many triangles near the camera
and too few where it matters. The Terrain component draws it as a quadtree of squares round the eye, every square the same small
patch, so a hill underfoot is drawn in fine cells and the same hill on the horizon in cells many times as large.
The component
Section titled “The component”Add a Terrain component to an entity. It is placed at that entity; its children are the quadtree’s nodes, made when the scene runs
(and in the editor’s scene view) and moved as the eye moves. Nothing is baked into the scene and nothing is saved besides the component.
The ground is one of two kinds, chosen by extent:
- Area: ground
sizeXbysizeZ, centred on the entity, from a heightmap or, without one, a window on its provider’s ground read where the area stands in the world (so two areas of the same size and noise side by side join, and an area is the same ground its provider gives without end; moving it moves the window, not the ground). It may be worn by rain and painted by a splatmap. - Infinite: ground made by a provider (below) read at any point in the world, so it has no edge. The same provider, world, seed
and version are the same ground everywhere, in the editor, in a game and on a server. It is drawn round the eye out to
drawDistance.
| Field | What it does |
|---|---|
extent |
Area or Infinite, as above. |
heightmap |
Area only. An image read as data: its bytes as the file holds them, with no colour conversion, so it ships as the PNG it is (a heightmap compressed on the way fails the terrain, saying so). Empty makes the ground from noise. |
heightmapFormat |
How the heightmap holds its heights. Grey: the grey (or red) channel, at the depth of the file: 16 bits from a 16-bit PNG (what World Machine, Gaea and most tools export), 256 steps from an 8-bit one. Red + green: sixteen bits across red (high byte) and green (low byte) of an 8-bit image. |
sizeX, sizeZ, height |
An area’s world size and the world height of its highest ground. For infinite ground sizeX is the span that frequency hills are spread over, and sizeZ is not used. |
cellSize |
The finest cell of the ground’s mesh, in world units: what the ground is drawn at near the eye. Further off the cells double, level by level. |
detail |
A multiplier on how far the finest cells reach before the ground coarsens. Above 1 is finer at a distance and costs more triangles. |
drawDistance |
Infinite only. How far from the eye the ground is drawn. |
collision, collisionDistance |
Whether 3D bodies and characters collide with the ground, and how far round each one that moves the ground is built for it. collisionLayer and friction (advanced) are the ground’s layer and grip. |
provider, world, generatorVersion |
Infinite, or an area with no heightmap. The generator the ground is made by (estella:noise, the engine’s noise, or one the game registers), the world it belongs to as the game names it, and the generator version that world was made with. |
seed, frequency, octaves, persistence, ridged |
The noise: another seed is another ground; frequency is how many hills across; ridged goes from rolling hills to sharp ridges. |
resolution |
Area only. Samples along each side of an area’s noise ground. |
warp |
0 to 1: how far the noise is bent by noise of its own, which gives winding valleys and bent ridges instead of round hills. |
erosion |
0 to 4: how much rain wears the ground (below). 0 leaves it as made. |
splatmap |
Area only. An image whose four channels are the weights of layers 1 to 4. Empty paints by height and slope. |
splatmap2 |
Area only. The weights of layers 5 to 8, read with the first. |
layers |
The terrain layers the ground is drawn with, up to eight, in the order the paint weighs them. Empty draws the four layer colours or the Terrain material’s textures. |
rockSlope, dirtHeight, snowHeight |
How steep ground must be to turn to rock, and the heights, as a share of height, where grass gives way to dirt and where snow begins. |
layerColor0–3 |
Grass, dirt, snow, rock: the colours the ground is drawn in when it has no material. |
material |
A material on the Terrain shader (below), or on Terrain Layers when the ground has layers. Empty uses the stock one. |
Changing detail, drawDistance or a layer colour takes effect on the next frame. Changing any other field builds the ground again.
Erosion
Section titled “Erosion”On an area, erosion runs rain over the field drop by drop, one drop for every sample of the field at 1: each drop runs downhill,
cuts the ground where it can carry more than it does and lays it down where it slows, which leaves gullies down the slopes, sharper
ridges between them and silt in the valleys. The same seed wears the same ground. It works on a heightmap’s field as well as a noise one. Where the water
ran the grass is taken and dirt is painted in its place, so the channels show. Rain over a large field is seconds of work, so it is
spread over frames and shown as it runs (see Building over frames).
Infinite ground has no edge for rain to run off, so its erosion is the noise’s own: each octave of the noise is damped where the octaves under it are already steep. That leaves smooth valleys between sharp ridges, much as rain would, at no cost beyond the noise. It paints no dirt channels.

The Terrain & Water example: layered ground, a river and the sea, all from the Terrain and Water components.
Terrain layers
Section titled “Terrain layers”A terrain layer (a .esterrainlayer file; New → New Terrain Layer in the editor) is one kind of ground — grass, a path’s dirt,
sand, rock — as the textures an artist made for it. A Terrain lists the layers it is drawn with (layers, up to eight), and its
splatmaps weigh them: the first’s red, green, blue and alpha are layers 1 to 4, the second’s layers 5 to 8. Without splatmaps the
first four are painted by height and slope as grass, dirt, snow and rock, and a generated world’s biomes can
paint all eight.
| Field | What it is |
|---|---|
albedo |
The colour, sRGB. Empty is white, coloured by the tint. |
normal |
A tangent-space normal map, green up (the OpenGL convention). Empty is flat. |
mask |
Red the ambient occlusion, green the roughness, blue the height. Empty: no occlusion, roughness, and the albedo’s brightness as height. |
tile |
How many world units one repeat of the textures covers. |
tint |
Multiplies the albedo. |
roughness |
The roughness where there is no mask. |
normalStrength |
How strongly the normal map bends the light: 1 as drawn, 0 flat. |
heightBlend |
Optional. How much this layer’s own height decides where it meets another: 0 blends by the paint alone (grass into sand), 1 by the layers’ heights (stones standing through grass). Where several layers meet, each counts by how much of it is there. Absent, it is the material’s u_heightBlend. |
The ground is drawn by the Terrain Layers shader (builtin:terrain-layers). Every layer is read by world position without repeat
near the eye, with a wider tile mixed in far off; where layers meet, the one whose mask stands higher shows (stones through grass, sand
between stones); on a slope each is also projected from the sides, so a cliff is not stretched. The normal maps and the masks’
occlusion and roughness light it. Its material sets how: u_sharpness, u_heightBlend, u_blendNoise, u_antiTile, u_farScale,
u_macroVariation, u_triplanarFrom (how steep before the sides are read) and u_wetLevel/u_wetBand, as the Terrain shader’s below.
What an artist delivers, per layer: the three textures, square, a power of two (1024 is plenty; they are packed at the largest layer’s size, at most 1024, 512 on a minigame), tiling seamlessly, the normal and mask saved as data (not colour-managed). A layer’s textures are packed into texture arrays when the terrain is built, and again whenever a layer file or one of its textures is saved.

The Terrain component: its layers, then the shape of the ground and where its heights come from.
Layers and the Terrain material
Section titled “Layers and the Terrain material”The four layers are grass, dirt, snow and rock. Every point of ground has a weight of each layer, from the splatmap or from how high
and how steep the ground is there, and the Terrain shader (builtin:terrain) draws them. The textures are tiled by world position,
so a layer runs unbroken across the ground however it is cut, and the rock is projected from three sides so a cliff is not a smear.
| Parameter | What it does |
|---|---|
u_layer0–3 |
The layers’ textures: grass, dirt, snow, rock. |
u_tint0–3 |
Each layer’s colour, which multiplies its texture. |
u_tile0–3 |
How many world units one repeat of each layer covers. |
u_sharpness |
How much the layer with more weight takes over at a seam: 1 is a plain blend, higher a harder edge. |
u_heightBlend |
How much the seams follow the layers’ own relief (their brightness): rock shows through the gaps in the grass before the grass gives way, and sand fills the low places between stones. 0 is a plain blend of the weights. |
u_antiTile |
How much of each layer is read a second time, turned and on a wider tile, and blended in by slow noise, so no repeat is seen across a field. It fades out with distance, where a repeat is too small to see. |
u_macroVariation |
A wide, slow variation in brightness laid over every layer so a big meadow is not one colour. |
u_relief |
How deep, in world units, the layers’ relief is drawn into the light (their brightness taken as height). 0 leaves the ground smooth. |
u_wetLevel, u_wetBand |
Ground at the water: below u_wetLevel + u_wetBand (world heights) it darkens and shines, most at u_wetLevel. A band of 0 draws none. |
u_roughness |
The ground’s roughness where it is dry. |
The shader’s other parameters (u_heightPages, u_lodRange0 and the like) are written by the Terrain component every frame;
a material leaves them alone.
How the ground is drawn
Section titled “How the ground is drawn”The ground is cut by a quadtree. Every node of the tree, at every level, is drawn with the same patch of 32 by 32 cells, scaled to the
node’s square: a level-0 node is 32 * cellSize across, and each level up is twice as wide, so its cells are twice as large. Each
level has a range from the eye. Level 0’s is 2.5 * 32 * cellSize * detail, and each level’s is twice the one below’s. A node nearer
the eye than the range of the level below it is split into its four children, so the ground is finest round the eye and coarsens level
by level with distance. An area has enough levels for a top node to be as wide as the area; infinite ground has enough for the top level’s range
to reach drawDistance.
The nodes are ordinary MeshRenderer children of the terrain entity, all of one mesh and one material, which the renderer draws
as instances: the whole ground is a handful of draws. The patch itself is flat. The Terrain shader lifts each vertex to the ground’s
height, read from the node’s page (below), and gives it the ground’s normal from the same page.
Toward the end of its level’s range, the shader slides each vertex onto the grid of the level above (geomorphing). By the edge of the range every vertex of a fine node lies where the coarser node beside it has one, so two levels meet along the same line: there are no cracks and nothing to hide them with, and nothing pops as the eye moves.
The heights a node is drawn with are kept in a page: the node’s square sampled 64 times along each side (two samples to a patch cell), with one more past each edge so the slope at the edge is known. A page holds the height in 16 bits over the ground’s range and the normal, in one atlas texture, and the weights of the four layers in another; each atlas is 2048 by 2048 and holds 900 pages. A coarse node’s page covers more ground at the same 64 samples, so its detail falls off with its cells.
Pages are made as the tree asks for them, a few each frame within a time budget, coarse and near ones first. Until a node’s page is made, the node is drawn by its nearest ancestor that has one, so the ground is there at once and sharpens as the pages come in. When the atlas is full, the page drawn least recently gives up its place.
Building over frames
Section titled “Building over frames”Making pages and wearing an area by rain are spread over frames rather than done in one, so neither holds up a frame. While they run they are listed with their progress (“Building the terrain”, “Eroding the terrain”) in the editor’s status bar, and a game can read the same list to show a loading screen.
From code
Section titled “From code”Terrain is an optional module: a package carries it when a scene has a Terrain, or when a script imports esengine/terrain (as below). A game with neither ships none of it.
The ground can be asked how high it is, for putting things on it:
import { TerrainsRes } from 'esengine/terrain';
const terrains = app.getResource(TerrainsRes);const y = terrains.heightAt(x, z); // world height, or null where there is no terrainconst n = terrains.normalAt(x, z); // the unit normal there, or nullThese read the surface: the lattice of cellSize cells, each node as high as the source says there, each cell cut in two along the
diagonal from its (1, 0) corner to its (0, 1) corner. That is exactly the finest level the ground is drawn at near the eye and what
bodies collide with, so a query, a ray and the drawn triangles agree (to the GPU’s 16-bit height encoding, a few millimetres for a
few hundred units of height), and the answer does not change with the camera. normalAt is the normal of the triangle there. They
answer for any point whether or not its page has been made. Until an area’s images are read and its erosion is done, heightAt
returns null and terrains.loading is true. A provider that answers later leaves a point null until the samples round it come in.
terrains.status(entity) says where a terrain stands: loading, ready, or failed with a reason. A terrain whose heightmap
cannot be read, whose provider is not registered, or whose version its provider no longer has fails: it draws nothing and answers
null, rather than growing noise where the game expected its own ground.
Collision
Section titled “Collision”With collision on, the ground is built for the 3D physics world in tiles of 32 cells within collisionDistance of every 3D body
that moves and every character: the tile under one at once, the rest a few a frame, nearest first, and let go once nothing is near.
Each tile is a static mesh body owned by the terrain entity, so a ray or a contact that hits the ground reports the terrain. While a
terrain is rebuilt its old tiles stay until the new ones replace them, so nothing standing on it falls.
terrains.collisionReadyAt(x, z) says whether the ground under a point is built, for a game to wait on before it drops something
there (a provider that answers later builds a tile once its samples are in). Far from anything that moves there is nothing in the
physics world to hit; terrains.raycast(origin, direction, maxDistance) meets the same triangles anywhere, with no physics, for a
long line of sight, a pick or a landing spot.
The tiles are meshes rather than a compressed heightfield shape on purpose: a heightfield shape quantizes its samples and cuts its cells its own way, and the ground that is collided with would no longer be the ground that is drawn and queried.
The tiles go through the CollisionGeometry resource (esengine), which any system that makes static geometry as the game runs can
use; the 3D physics world keeps one static body for each piece in it.
Modifiers
Section titled “Modifiers”A game changes the ground where it needs to (a plot levelled to build on, a pad, a road’s bed) with modifiers: functions of the world
position and the height the ground has there, each over a square of the world. They are laid over whatever the terrain’s ground is,
in the order they were set, and every reader follows them: what is drawn, heightAt and normalAt, rays and collision. Only the
pages and collision tiles a modifier reaches are made again, and what stands on the ground (plants, water, a generated world) is placed
again.
import { flattenModifier } from 'esengine/terrain';
const terrains = app.getResource(TerrainsRes);const level = terrains.heightBeneathAt(x, z)!; // the ground as it was made, under every modifierterrains.setModifier(flattenModifier('plot 1', { type: 'rect', x, z, halfX: 40, halfZ: 30, yaw }, level, 12));terrains.deleteModifier('plot 1'); // the ground comes backA WorldZone with flatten levels its ground this way.
Can it be walked to
Section titled “Can it be walked to”findPath searches the ground for a way from one place to another that a walker held to a slope can take: what a game checks a
spawn, a quest’s goal or a village against before it trusts a generated world. It reads the ground where the search goes (modifiers
and all), so it needs nothing baked and works on ground without end.
const terrains = app.getResource(TerrainsRes);const waters = app.getResource(WatersRes);const way = terrains.findPath(spawn, village, { maxSlope: 32, // degrees; a walker switches back up anything gentler across step: 8, // the search's cell, in world units blocked: (x, z) => (waters.shoreAt(x, z) ?? 1) < 0, // no wading});if (way.state !== 'reached') regenerate(); // 'unreachable', 'exhausted' (ran out of maxCells) or 'noGround'The way comes back pulled straight wherever a straight walk holds, with its length along the ground. It is a query for checks and
plans, not for every frame: a few hundred metres cost milliseconds, and maxCells bounds a long one, which then says it ran out
rather than that there is no way. Agents that walk every frame use navigation.
Providers and versions
Section titled “Providers and versions”Ground without end is made by a provider: one function of the world position, the same on every machine. It is asked for a region (the world, seed and version, a corner in world units, a spacing and a count of samples a side) and answers the heights there, and, if it paints the ground, four layer weights a sample. Every region is the same function read at other points, so neighbouring pages share their edge’s samples, a coarse page and a fine one agree where their samples meet, and the order pages are made in changes nothing. Positions are the world’s, not the terrain’s: two terrains placed apart over one world are the same ground.
import { registerTerrainProvider, type TerrainProvider } from 'esengine/terrain';
const planet: TerrainProvider = { id: 'mygame:planet', versions: [1, 2], // every version a saved world may still name range: (seed, version) => [-200, 900], // the least and most height, which the GPU encodes over sample({ world, seed, version, x0, z0, spacing, count }) { const heights = new Float32Array(count * count); // ... heights[j * count + i] at (x0 + i * spacing, z0 + j * spacing) return { heights }; // or a Promise, from a worker or a server },};registerTerrainProvider(planet);A version names an algorithm for good. A saved world keeps generatorVersion; when the algorithm changes, add a version and keep
the old one, so what was built on the old ground still stands on it. The engine’s noise is estella:noise, version 1. A provider
with heightAt answers a point at once; without it a point is answered from small sampled tiles at the finest cell size.
A planet
Section titled “A planet”A Planet is ground on a sphere. It is the same machinery as the ground above with a round world under it: a cube whose six faces are each a quadtree, every point pushed out to
the radius, so the finest cells are under the eye and a planet seen from far off is a handful of coarse nodes. The same ground is drawn from the surface and from space, with nothing
to switch between.
| Field | What it does |
|---|---|
radius |
The planet’s radius in metres. The planet stands at its entity, unrotated and unscaled. |
provider, world, generatorVersion, seed |
The generator the ground is made by (registerPlanetProvider), the world it belongs to as the game names it, its version and its seed. The same four are the same ground everywhere. |
cellSize, detail |
The finest cell of the ground’s mesh in metres, and how far out the finest cells reach (above 1 is further). |
layerColor0–3, macroScale, macroVariation |
The four layers’ colours (grass, dirt, snow, rock), and the wander in brightness laid over them: macroScale is its size in metres, macroVariation its strength (0 to 1). |
layers |
Up to four .esterrainlayer files the ground is drawn with; empty draws the four colours. |
collision, collisionDistance, collisionLayer, friction |
As on a flat terrain: whether bodies collide, how far round each moving body the ground is built, its layer and its grip. |
gravity |
How hard the planet pulls what is on it, in metres a second squared at the surface; 0 (the default) pulls nothing. |
sea, seaLevel, seaColor, seaOpacity |
Whether the planet has a sea, its height above the radius, its colour and how much of it covers what is under it (0 to 1). |
A planet’s provider answers for directions, not positions: it is handed unit directions from the planet’s centre and the radius they are on, and gives back each one’s height above the radius and, if it paints, four layer weights. A sphere has no x and z, so a generator reads three-dimensional noise at the point’s place, which has no seam and no pole.
registerPlanetProvider({ id: 'my-game:planet', versions: [1], range: () => [-40, 200], sample({ seed, radius, directions, count }) { const heights = new Float32Array(count); for (let i = 0; i < count; i++) heights[i] = myHeight(seed, radius, directions[i * 3]!, directions[i * 3 + 1]!, directions[i * 3 + 2]!); return { heights }; },});A planet answers the questions a round world puts to everything standing on it, through the PlanetRegistryRes resource: up(planet, x, y, z) is the unit direction away from its centre, altitude the height above the radius, groundHeight the generator’s own height under a position (null while a provider answers later) and groundPoint the point on the ground under it. nearest(x, y, z) names the planet whose surface is nearest. Set gravity (metres a second squared at the surface) and 3D physics pulls every dynamic body toward the centre of the nearest planet that pulls: the world’s one gravity is taken off the body and the planet’s put on, as a force each fixed step, so with the world’s gravity at zero a body simply falls toward the planet.
A generated world can be laid out over a planet: put a WorldGen with surface set to Planet on the Planet’s entity. Each of the cube’s six faces is laid out as a plane of metres by the same rules a flat world has (biomes over fields, recipes, layers), a direction is planned by the face it falls on, and what is placed is taken to the planet and stands along its up. The fields are the planet’s own: the ground’s height, its slope, noise read in three dimensions (so a field wanders over an edge between two faces with no seam), paint.<layer> for each of the planet’s layers, and the fields the provider names with fields (an ecology). The biomes also paint the ground (paintGround), so what is drawn and what grows are one map. seaLevel is the height of the sea: lower ground is under water. Zones (WorldZone) stand at a position in the world and are kept on the face they fall on.
The ground collides: the finest nodes within collisionDistance of every moving 3D body and character are built as collision geometry from the same samples the ground is drawn from (collision, collisionDistance, collisionLayer, friction, as on a flat terrain). A planet’s transform is a position only: a turned or scaled planet’s collision stands where it would be unturned. layers names up to four .esterrainlayer files, as on a flat terrain; each is read on the planes of the world’s axes by how much the ground faces them, with a wider read mixed in far off so the repeat is lost. Without layers the ground is the four colours. A planet’s provider can hand the engine its generator as a module a worker can load (workerSource: the text of a self-contained module of plain JavaScript whose default export answers sample, fields, versions and id). The world is then laid out and the ground painted on worker threads, and the main thread only puts each answer in the world as it arrives; without it everything is done on the main thread as before.
Set sea and the planet has a sea: a translucent, lit sphere at seaLevel above the radius, in which the ground that dips below it stands (waves and shore foam are the flat water’s and come to the sphere later). The sky follows the horizon round: give skyAtmosphere and heightFog the planet’s radius and centre and they work out the sky and the haze for the ground the camera stands on, with the sun a fixed direction, so a place’s day and night are where it is on the planet.
Blending what stands on the ground
Section titled “Blending what stands on the ground”Three things hide the line where a model meets the ground. None of them needs the ground to know.
The Ground Blend material. The builtin:ground-blend shader is the Model shader, with every map and param it has, for a rock, a kerb or a foundation. Where the surface comes close to what stands behind it, it gives way to the picture of that very pixel, so whatever the ground is drawn with (its layers, its light, its shadows) is what the seam fades into, with nothing baked. It works on anything behind it, not only a terrain.
| Param | What it does |
|---|---|
u_blendDistance |
How high above what is behind the surface has fully arrived, in world units. It is a height and not a distance along the view, so the band holds as the camera tilts. 0 leaves a hard edge. |
u_blendNoise, u_blendNoiseScale |
How much the edge wanders, and the world size of its wander, so it is not a ruled line. |
u_layer2, u_layer2Tint, u_layer2Roughness |
A second layer: dirt, moss, wet stone. |
u_layer2Tile |
The length of one repeat of it in the world, read from above so it lines up across objects. 0 reads the mesh’s own uv. |
u_layerReach |
How far up from what is behind it the second layer climbs, as a distance field does. |
u_vertexBlend |
1 lets a vertex colour’s red paint the second layer, and stops the colour tinting the surface. |
Such a material is drawn after a copy of the opaque scene is taken, the way water is, and a scene with one takes that copy even with no post effect of its own.
A road. A RoadDecal on an entity with a Spline lays the entity’s MeshRenderer along the curve and over the ground, row by row, and is laid again when the spline or the ground changes. Each edge fades over edgeFade of its half width, so give it a blended material. With no terrain it lies along the curve as drawn.
| Field | What it does |
|---|---|
step, across |
How far apart its rows are along the curve, and how many cells across. Finer follows the ground and the bends more closely. |
widthScale |
Times the width each spline point says. |
lift |
How far above the ground it lies. Far off the ground is drawn coarser than it is asked, so a road seen from far needs more. |
edgeFade |
The share of its half width over which each edge fades. |
tile |
The length of one repeat of its texture along the curve. |
Snow and wet. The snowCover post effect lays snow on whatever faces the sky and stands under nothing, the terrain and the rock on it alike, with no material changed: u_amount, u_snowLine and u_snowLineBand (the height it stops at), u_slopeLimit and u_grainScale. The Snow weather brings it. The rain effect with u_intensity at 0 and u_wetness up is the same for a wet ground, under no rain.
Large ground: tiles
Section titled “Large ground: tiles”A heightmap is read whole: an 8193 by 8193 field is about 256 MiB. Point tiles at a .esterrain and the ground is kept as tiles of
513 by 513 samples (neighbours share their edge) and a low-detail overview.
- Distant ground is drawn from the overview, which is always in memory.
- Full-detail tiles are read only near the view or a moving body, and past 256 MiB the least recently used are let go. Where no tile has been read yet the height is not known, and collision and queries wait for it.
- Split into Tiles in the terrain sculpt panel converts a terrain.
- Tiled ground is sculpted and painted like any other, on the tiles in memory: a dab over a tile not read yet is skipped and the tile is read. A changed tile stays in memory until it is saved, and a save writes the changed tiles and the overview only.
- The sculpt panel exports the heights as one image the size of the area, and imports one over the tiles. With Loaded tiles no tile that is not in memory is read: an export takes the rest from the overview, and an import writes the tiles in memory and the overview only; All tiles reads and writes every one. An import is refused while there are changes not saved.
- The tile images are named only by the
.esterrain, so they are not preloaded and uploaded as textures the way aheightmapis.
Measured in the editor on a 4096-unit area: an 8193 by 8193 field opened as tiles holds 36 MiB, and 45 MiB close to the ground.
Limits
Section titled “Limits”-
It is a height for each place. A cave, an overhang or a hole needs Voxel Terrain, a separate ground that is a volume.
-
Collision is the finest level. Far off the ground is drawn coarser than it collides, which is unseen from where anything collides with it; only what moves gets ground to hit, within
collisionDistance. -
Paint is as fine as the pages. Layer weights are sampled with the heights, two to a cell, so a splatmap finer than that near the eye is averaged, and far off it is coarser still.
-
No holes, caves or overhangs. A heightfield has one height at each place. Caves and bridges are meshes placed with it.
-
Position only. The terrain follows its entity’s position; its rotation and scale are not taken into account, by
heightAtor by the shader that lifts the ground. Keep the entity unrotated and unscaled, and set the ground’s size withsizeX,sizeZandheight. -
An infinite ground is made by its provider. It takes no heightmap or splatmap, and its erosion (the engine’s noise) paints no dirt.
-
Ground Blend fades into what is seen behind it. Where nothing is close behind the surface (a rock’s side seen against a far valley) there is no seam to hide and none is hidden. A wall just behind a Ground Blend object counts as close, as the ground does. Two such objects do not fade into each other: neither is in the copy the other reads. It needs float render targets; without them it draws as a plain Model.
-
snowCoveris laid on the picture. It has no depth, so it does not round an edge or bury a stone, and it is limited to what the camera sees. -
Pages are made a few a frame, so on the first frames, or after a jump of the eye, the ground is drawn coarse for a moment and sharpens rather than stalling a frame.