Sand Simulation
REQUIREMENTS ... - Not supported: Built-in, HDRP, WebGL LIMITS ... Sand that remembers what walked across it. ... The displaced sand piles up around the rim rather than vanishing.
by AssetMustard
Price History +
SIMULATION
- GPU height field, seven compute kernels: init, carve, spread, repose relaxation, wind, brush, bedrock bake
- Displacement with conservation: sand removed from a footprint is piled around its rim
- Angle of repose, 20-55 degrees, symmetric cell exchange so the volume holds
- Wind transport as paired flux, out of one cell and into the next - no drift or mass loss over long sessions
- Bedrock floor: digging bottoms out on rock instead of going forever, and exposed rock is shaded as stone
- Resolution 256 / 512 / 1024 cells, field size 20-400 m. 120 m at 512 is a 23 cm cell
- Relaxation passes per frame adjustable 0-8; wind can be switched off to skip the pass entirely
RENDERING
- Custom URP surface shader with a matching shadow caster, both sharing one height function
- One draw call, one mesh, height read in the vertex stage - no CPU mesh work
- Wind ripples, slip-face shading and rock grain, with a distance fade so they do not alias
- Exposed material properties: sand and rock colours, ripple depth, sparkle, roughness, sand cover depth
RUNTIME API
- SampleHeight(worldPos) and SampleNormal(worldPos) for standing on the surface and reading slope
- ApplyBrush(worldPos, radius, metresPerSecond, mode) - raise/lower, smooth, flatten
- Regenerate() and Flatten()
- Async GPU readback at ~12 Hz, so height queries never stall the frame
DEFORMERS
- SandDeformer component: radius, vertical offset, active flag. Registers itself on enable
- Up to 32 considered per frame
- Sphere-based, so any mesh shape works - use several for a capsule or a box
EDITOR
- Setup window: creates and wires a field in one click, adds a low sun, attaches deformers to a selection
- Custom inspector with four material presets (dry dunes, packed sand, fine dust, gravel)
- Live cell size, memory and deformer count readouts
- Startup checks report a missing compute shader, a non-URP pipeline or a GPU without compute support
PERFORMANCE (512 x 512 over 120 m, desktop GPU, 1440p, demo running)
- Simulation ~0.5 ms/frame
- Height field memory 5 MB
- 1 draw call, 262k triangles
- 170-290 fps
PACKAGE
- Full C# source, no DLLs, no third-party assets, no textures - everything is procedural
- Runtime in its own assembly definition that references nothing but the engine
- Namespaced throughout; Editor and Demo folders can each be deleted without breaking the runtime
- Two demo scenes: first person walking, digging and boulder throwing, and a top-down sculpting sandbox
- Demos run on either input backend; the Input System package is not required
- Manual and changelog included
REQUIREMENTS
- URP only, Unity 6000.0 or newer
- Compute shader support: Shader Model 5.0, or GLES 3.1 with compute
- No URP asset changes needed - no Depth Texture, no Opaque Texture, no custom Renderer Feature
- Not supported: Built-in, HDRP, WebGL
LIMITS
- Height field: no overhangs, no caves, no sand falling off a ledge
- No collider - the surface is a GPU texture, so use SampleHeight rather than raycasts
- Wind ripples are shading, not geometry
- Two fields can overlap in world space but will not exchange sand
Sand that remembers what walked across it.
SandSim is a deformable desert surface for URP, simulated on the GPU as a height field. Anything you tag with a SandDeformer presses into it - feet, tyres, a dropped crate, a rolling boulder. The displaced sand piles up around the rim rather than vanishing. Slopes that end up too steep collapse on their own, and the wind slowly softens tracks and creeps the dunes.
Because it is a texture and not particles, the cost does not change as the ground gets churned up. A desert covered in an hour of footprints renders in the same single draw call as a pristine one.
WHAT IT SIMULATES
Displacement - sand pushed out of a footprint ends up around its rim, so marks look pressed in rather than stamped on.
Angle of repose - dry sand will not hold a slope past about 34 degrees. Dig a hole and the walls slide back in. Pile sand up and it settles into a cone by itself.
Wind transport - sand lifted off one cell lands on the next one downwind. Tracks soften over time, dunes creep. Turn it off entirely if you want marks to stay put.
Bedrock - sand sits on rock and is never carved below it, so digging bottoms out instead of going forever. Where the rock rises above the dunes it shows through as a shaded outcrop.
TUNING
Every number is exposed on the component and takes effect live. Four one-click presets cover the usual materials:
Dry dunes - loose, slumps easily, wind keeps working on it
Packed sand - beach above the tide line, holds a steeper face
Fine dust - collapses at the slightest touch, drifts constantly
Gravel - coarse and stubborn, steep piles, no wind transport
Past the presets you control the angle of repose, flow rate, relaxation passes, wind direction and strength, dune height, scale and direction, and the bedrock shape. The surface material exposes sand and rock colours, slip-face shading, wind ripples, sparkle and roughness.
USING IT IN A GAME
float y = field.SampleHeight(worldPos); // stand on it
Vector3 n = field.SampleNormal(worldPos); // read the slope
field.ApplyBrush(worldPos, radius, metresPerSecond, mode);
That is most of the API. ApplyBrush is what an in-game shovel, an explosion crater or a vehicle plough calls. Heights are read back to the CPU a few times a second, which is what lets a character walk on dunes it is busy digging out from under itself.
WHAT IT SUITS
Desert survival and exploration, where footprints and dig sites are the point. Off-road and dune-buggy driving, where tracks matter. Top-down builders and god games - the included sculpting demo is exactly that loop. Excavation and archaeology games. Anywhere a beach, quarry, ash field or gravel pit needs to respond to being walked on.
It is not a terrain replacement. Think of it as one patch of responsive ground you place where the player actually is.
INCLUDED
SandField and SandDeformer - the whole runtime, in an assembly that references nothing but the engine
SandSim/Sand surface shader with a matching shadow caster
Setup window that wires a field into your scene in one click
Custom inspector with presets and live cell-size and memory readouts
Two demo scenes - first person walking, digging and boulder throwing, and a top-down sculpting sandbox
Full manual: parameters, how the simulation works, performance figures, and the things that will otherwise catch you out
PERFORMANCE
512 x 512 cells over 120 m, desktop GPU at 1440p, demo running:
Simulation ~0.5 ms/frame
Memory 5 MB
Draw calls 1
Frame rate 170-290 fps
The fragment shader is the expensive half, not the simulation. Halving the resolution is a 4x saving if you need it.
REQUIREMENTS
URP. There is no Built-in or HDRP variant.
Unity 6000.0 or newer.
Compute shader support - Shader Model 5.0, or GLES 3.1 with compute. WebGL cannot run this.
No URP asset changes are needed: no Depth Texture, no Opaque Texture, no custom Renderer Feature. It works with whatever Renderer you already have. The demos run on either input backend, and the Input System package is not required.
LIMITS, STATED UP FRONT
It is a height field. No overhangs, no caves, no sand pouring off a ledge.
There is no collider. The surface lives on the GPU, so raycasts pass through it - use SampleHeight instead. The demo character does exactly this.
32 deformers are considered per frame.
Wind ripples are shading, not geometry.
Two fields can overlap in world space but will not exchange sand.