AssetPro - WorldGen — Runtime Procedural Infinite Terrain Generator

WorldGen is a runtime C++ plugin for Unreal Engine 5 that generates infinite procedural terrain with async chunk streaming, layered noise, biome blending, and foliage scattering — all without blocking the game thread.

Drop WorldStreamingManager into your level and get a fully streaming open world in minutes.

V1.1 adds a dedicated dense grass system with player-radius culling, per-asset resolution/radius control, and slope-aware instance sinking.

V1.2 adds hydraulic erosion — particle-based droplet simulation that carves valleys, sharpens ridges, and deposits sediment, running entirely on the background thread.

V1.3 adds multiplayer support — terrain streams around every connected player simultaneously. Dedicated servers build collision only, skipping all visual and foliage work.

V1.4 adds terrain deformation (experimental) — sculpt terrain in real-time with configurable spherical brushes. Includes fixes to texture world scaling and foliage grid placement independence from mesh resolution.

V1.5 adds distance-based LOD — configurable resolution tiers per ring distance keep near-terrain high-polycount for smooth deformation while reducing memory and build cost at distance.

V1.6 adds three critical production fixes: (1) Floating-point precision fix eliminates texture stretching at extreme world distances (2M+ units) by using local coordinates for UV math instead of world coordinates. (2) Dynamic road expansion — roads now generate deterministically in all chunks as the player explores, with automatic pathfinding to the existing network. (3) Erosion safeguard — erosion is automatically disabled at low LOD resolutions (≤32) to prevent artifacts, and the LOD array is optimized to [256, 256, 128, 64] for the best quality-to-performance balance.

V1.0 Preview Video

Playable Demo

V1.1 Dense Grass Video

──────────────────────────────

CORE FEATURES

──────────────────────────────

▸ Infinite Chunk Streaming — actor pool recycles chunks at runtime (no spawn/destroy overhead). Configurable view distance up to any radius.

▸ Async Mesh Generation — geometry built entirely on a thread pool. Game thread is never blocked.

▸ Async Collision Cooking — bUseAsyncCooking enabled by default.

▸ Seamless Chunk Normals — 1-vertex border overlap ensures no visible seams between tiles.

▸ Layered Noise Stack — stack up to N noise layers. Layer 0 acts as a continental mask controlling where mountains appear vs flat plains.

▸ FastNoise Lite Integration — Perlin, OpenSimplex2, Cellular, Ridged Multifractal, Domain Warp Progressive (MIT licensed, ships with source).

▸ Domain Warping — global warp offsets applied to all coordinates for natural terrain variation.

▸ Biome Blending — vertex color blend weights for Grass / Rock / Snow / Beach / Underwater. Plug directly into any landscape material.

▸ Beach Layer — configurable height band above sea level. Beach weight baked into UV1.x for smooth sand transitions.

▸ Foliage System — BiomeFoliageAsset data assets drive HISM scatter on the thread pool. Per-mesh density, height, slope, and scale constraints. Per-entry collision toggle — enable only on meshes that need physical interaction.

▸ Dense Grass System — UWorldGenGrassAsset data assets drive ISM ground cover on a dedicated high-resolution grid independent of mesh resolution. Grid is world-snapped and player-radius culled (identical behaviour to Landscape Grass Output). Per-asset Grass Resolution, Grass Radius, density, slope constraints, scale, and normal alignment. Grass follows the player seamlessly at runtime.

Hydraulic Erosion — particle droplet simulation with configurable strength, deposition, evaporation, sediment capacity and brush radius. Fully async, zero game thread cost. Enable per-world with a single toggle. (V1.6: Auto-disabled at low resolution for artifact prevention)

▸ Slope Sink Depth — automatically sinks grass blades into the terrain on slopes to prevent floating. Scales with sin(slope angle), configurable per asset. Instances reused across chunk recycling.

▸ Terrain Deformation — sculpt terrain in real-time using spherical brushes. Deformation persists when chunks reload. (Experimental)

▸ Distance-Based LOD — configurable per-ring resolutions keep high vertex density near the player while reducing memory and build cost at distance. (V1.6: Optimized default array [256, 256, 128, 64])

▸ Road Network — terrain-following roads with corridor flattening and foliage removal. (V1.6: Dynamic expansion — roads generate in newly discovered chunks as the player explores)

Floating-Point Precision Fix (V1.6) — eliminates texture stretching at extreme world distances (2M+ units) by using local coordinates for UV calculation. Critical for open-world exploration beyond a few million units.

▸ Multiplayer Support — terrain streams around all connected players simultaneously. Each player's chunk position is tracked independently. Per-player gravity delay applied on spawn, including late joiners.

▸ Dedicated Server Mode — on a dedicated server, WorldGen builds collision geometry only. Visual mesh, foliage, and grass are skipped. Server cost scales with player count, not visual quality.

▸ Water Plane — follows player on a configurable timer. Covers full view distance.

▸ Editor Preview — CallInEditor button rebuilds terrain without entering Play mode.

──────────────────────────────

TECHNICAL HIGHLIGHTS

──────────────────────────────

▸ Pure C++ runtime — no Blueprints required (Blueprint-friendly exposed parameters)

▸ ProceduralMeshComponent-based geometry

▸ Fully exposed parameter categories with tooltips and clamped slider ranges

▸ Seeded RNG per chunk — deterministic foliage placement

▸ Terrain Coverage readout in the Details panel (e.g. "9 × 9 chunks — 9.0 km × 9.0 km")

▸ Grass and foliage collision independently toggleable per asset entry

▸ Listen server, client, and dedicated server configurations supported with no additional setup

──────────────────────────────

INCLUDED

──────────────────────────────

▸ Full C++ source

▸ Pre-built landscape material (M_LandscapeAutoTextured) with biome blending wired up

▸ Sample foliage and grass data assets (grass biome)

▸ Sample tree and pine meshes with materials

▸ Demo map

──────────────────────────────

PERFECT FOR

──────────────────────────────

Open-world games, survival games, exploration prototypes, procedural world tools, and any project needing infinite streaming terrain without writing low-level noise or chunk management code. V1.6 is production-ready with critical floating-point precision fixes verified for games requiring exploration at extreme world distances.

──────────────────────────────

ADDITIONAL NOTES

──────────────────────────────

  • Requires the ProceduralMeshComponent plugin (bundled with Unreal Engine 5, enabled by default).

  • Includes FastNoise Lite (MIT license, Jordan Peck / Auburn) — ships in plugin source tree, safe for commercial use.

──────────────────────────────

WHAT'S FIXED IN V1.6

──────────────────────────────

Texture Stretching at Extreme Distance (CRITICAL)

Eliminated diagonal checkerboard stretching pattern that appeared at 2M+ units from world origin. Root cause: UV coordinates calculated using absolute world coordinates. At extreme distances, single-precision floats lose precision in division, causing uneven texture sampling. Fix: Use local coordinates (relative to chunk origin) for UV math. One-line change, massive visual impact.

Dynamic Road Expansion (FEATURE)

Roads now generate deterministically across the entire world as the player explores. Previously, roads only appeared in chunks loaded at BeginPlay. V1.6 adds ExpandRoadsForChunk() which automatically pathfinds new roads to the existing network when new chunks are discovered.

Erosion Safeguard (STABILITY)

Erosion simulation automatically disables at resolution ≤32 to prevent unacceptable artifacts. Combined with the optimized default LOD array [256, 256, 128, 64], terrain is now stable at all recommended resolutions without visual glitches.

Playable Demo

V1.0 Preview

V1.1 Dense Grass Video

V1.2 Erosion Video

V1.3 Multiplayer Support Video

V1.4 Runtime Terrain Deformation

V1.5 Terrain LOD System

────────────────────

(post deleted by author)

WorldGen Plugin — V1.6 Documentation

By CodeLikeMe | UE5 | Runtime Infinite Terrain


Overview

WorldGen is a runtime infinite terrain streaming plugin for Unreal Engine 5.4–5.7. Unlike editor-time terrain tools, WorldGen generates and streams terrain while your game runs — no baking, no pre-generation, no loading screens. Chunks build on background threads, stream around the player seamlessly, and recycle without ever spawning or destroying actors at runtime.

Designed for: Indie developers building open-world games who want production-ready terrain streaming without writing engine-level code.

The core promise: Most terrain tools run in the editor. This one runs in your game.


What’s New in V1.6

Critical Bug Fixes (V1.6)

Fix Impact Status
Texture Stretching at Extreme Distance Eliminates diagonal checkerboard pattern at 2M+ units ✓ Fixed
Dynamic Road Expansion Roads now generate in all chunks as player explores ✓ Complete
Erosion Safeguard Prevents artifacts at low LOD resolution (≤32) ✓ Implemented

Verified & Tested (V1.6)

  • ✓ Smoke tested on UE5.5, UE5.6, UE5.7 (zero errors/warnings)

  • ✓ LOD array optimized: (256, 256, 128, 64)

  • ✓ All Fab submission requirements verified


What’s in V1.6 (Complete Feature List)

Feature Notes
Infinite chunk streaming Actor pool — no spawn/destroy at runtime
Async mesh generation Thread pool — game thread never blocked
Async collision cooking Background physics build
Seamless chunk normals 1-vertex border overlap eliminates lighting seams
FastNoise Lite Perlin, Simplex, Cellular, Ridged Multi, Domain Warp
Layered noise Up to N layers with continental masking
Domain warping Global XY warp applied before all layer evaluation
Far terrain Second low-res LOD ring for massive draw distances
Water plane Flat ocean at sea level, follows player on a timer
Beach layer Height-based sand zone with terrain flattening
Slope-aware blending No sand on cliffs; rock injected on steep faces
Underwater blend Per-pixel world-position Z cutoff — no vertex interpolation artifact
Material parameter sync SeaLevelZ auto-pushed to your terrain material
HISM foliage system Per-biome data assets, per-entry placement rules
Foliage clustering Natural clump patterns for trees and rocks
Per-entry view distance Trees at 4 chunks, ground clutter at 1
Grow in Shade Ground cover layers alongside trees without blocking
Per-entry foliage collision toggle Enable collision only on meshes that need physical interaction
Dense ISM grass system (V1.1) Radius-based world-snapped scatter grid — density independent of tile size
Per-asset grass radius & resolution (V1.1) Each grass asset controls its own spawn radius and grid density
Slope Sink Depth (V1.1) Auto-sinks blades into terrain on slopes, proportional to slope angle
Hydraulic erosion (V1.2) Particle droplet simulation — carves valleys, deposits sediment, fully async
Multiplayer support (V1.3) Server streams terrain around all connected players. Dedicated server builds collision only — no foliage, grass, or visual mesh
Per-player gravity delay (V1.3) Terrain load delay applied per-player including late joiners
Terrain deformation (V1.4) Sculpt terrain in real-time with spherical brushes; persistent height deltas; DeformTerrain() and ClearDeformation() API
Fixed texture world scale (V1.4) Texture scale now independent of tile size and resolution
Fixed foliage grid (V1.4) Foliage placement independent of mesh resolution
Distance-based LOD (V1.5) Configurable per-ring resolution array; high resolution near player, lower at distance; seamless transitions
LOD toggle (V1.5) Enable/disable LOD system; flat Resolution fallback when disabled
Increased resolution support (V1.5) Now supports 256+ vertices per side (previously capped at 128)
Texture Stretching Fix (V1.6) UV coordinates use local math instead of world math — eliminates precision loss at extreme distances
Dynamic Road Expansion (V1.6) Roads generate in newly discovered chunks as player moves; automatic pathfinding to existing network
Erosion Safety (V1.6) Erosion disabled at resolution ≤32 to prevent unacceptable artifacts
Enable/disable toggles Foliage, grass, erosion, deformation, LOD, and roads can be switched off independently
Road network A* terrain-following roads with corridor flattening and dynamic expansion
Editor preview Preview Terrain / Clear Terrain buttons in Details panel
Coverage label Live readout of loaded terrain footprint in km

Installation

  1. Copy the WorldGen folder into your project’s Plugins/ directory.

  2. Right-click your .uproject and choose Generate Visual Studio project files.

  3. Open the solution, build, and launch the editor.

  4. The plugin is automatically enabled — no manual activation needed.


Quick Start

1. Place the streaming manager

  • In the Place Actors panel search for WorldStreamingManager.

  • Drag one into your level. Place it roughly where you want the world origin.

2. Assign a terrain material

  • Create a material (see Material Setup below).

  • Assign it to WorldGen > Terrain Material on the streaming manager.

3. Preview in editor

  • Select the streaming manager and click Preview Terrain in the Details panel.

  • Terrain builds asynchronously — it appears within a second or two.

  • Adjust parameters and click Preview Terrain again to rebuild.

4. Play

  • Hit Play — terrain streams automatically around the player character.

  • No additional setup required.


Material Setup

WorldGen bakes all terrain blend weights into vertex data. Your material reads these channels to drive layer blending.

Vertex Color Channels

Channel Node in Material Value
VertexColor.R Vertex Color > R Water — 1.0 below sea level, 0.0 above. Binary step, not a gradient.
VertexColor.G Vertex Color > G Grass — base layer remainder
VertexColor.B Vertex Color > B Rock — height + slope based
VertexColor.A Vertex Color > A Snow — high-altitude cap

UV Channels

Channel Node in Material Value
UV1.R TextureCoordinate(1) > R Beach — 1.0 at waterline, fades to 0 at top of beach band
UV1.G TextureCoordinate(1) > G Road — 1.0 at centerline, 0 at corridor edge

Material Parameter

Parameter Name Type Set By
SeaLevelZ Scalar Auto-pushed by WorldStreamingManager at BeginPlay and on parameter change

Recommended Blend Order

Build your material as a chain of Lerp nodes, outermost last:

Grass (base)
  → Lerp(Grass, Rock,       Alpha = VertexColor.B)
  → Lerp(above, Snow,       Alpha = VertexColor.A)
  → Lerp(above, Beach,      Alpha = TextureCoordinate(1).R)
  → Lerp(above, Road,       Alpha = TextureCoordinate(1).G)       [optional]
  → Lerp(above, Underwater, Alpha = underwater_mask)

Underwater Mask (Per-Pixel — Recommended)

Replace VertexColor.R as the underwater Lerp alpha with a world-position comparison to eliminate waterline interpolation artifacts:

AbsoluteWorldPosition → Mask(B/Z)
  → Subtract(SeaLevelZ parameter)
  → Multiply(-1)
  → Divide(500)
  → Saturate
  → Lerp Alpha for Underwater layer

This runs per-pixel and produces a clean, artifact-free waterline on any slope.


Parameter Reference

All parameters are on the AWorldStreamingManager actor in the Details panel.

WorldGen | General

Property Default Description
Seed 42 Master world seed. Change for a completely different world.
Tile Size (cm) 200,000 Width/height of each terrain chunk. 200,000 = 2 km per tile.
Resolution 64 Vertices per side per chunk. Used as fallback when LOD is disabled.
Height Scale 1.0 Global height multiplier applied after noise.
View Distance (chunks) 4 Near-terrain chunk radius. 4 = 9×9 = 81 chunks.
Terrain Load Delay (s) 4.0 Seconds to suspend gravity at startup while async collision cooks. Increase if the player falls through terrain in the first few seconds. Applied per-player, including late joiners.
Terrain Material null Your terrain material (or material instance).
Enable LOD (V1.5) true Enable distance-based LOD system. When off, all chunks use flat Resolution.
LOD Resolutions (V1.5) [256, 256, 128, 64] Array of resolutions per Chebyshev distance ring. Index 0 = player’s chunk, 1 = one ring out, etc. Last entry reused for all further rings. Recommended (V1.6): [256, 256, 128, 64] — avoids resolution 32 artifacts.

WorldGen | Height Range

Property Default Description
Min Height (cm) -175,000 Ocean floor. More negative = deeper oceans.
Max Height (cm) 175,000 Mountain peak.
Sea Level 0.50 Normalized [0–1]. 0.5 = midpoint between Min and Max Height.

WorldGen | Terrain Layers

Property Default Description
Rock Start 0.65 Normalized height where rock begins. Must be above Sea Level.
Rock Blend 0.10 Grass->rock transition width. Small = sharp cliff edge.
Snow Start 0.75 Normalized height where snow begins.
Snow Blend 0.06 Rock->snow transition width.

WorldGen | Mountains

Property Default Description
Mountain Threshold 0.25 Controls mountain coverage. Raise for more flat plains.
Mountain Blend 0.30 Plains->mountains transition smoothness.

WorldGen | Noise

Property Default Description
Noise Layers 4 layers Stack of noise layers. Layer 0 is always the continental base.
Warp Strength 8,000 Domain warp amplitude in cm. 0 = disabled.
Warp Frequency 0.000033 Domain warp frequency.

Default Noise Layer Stack

# Name Type Frequency Octaves Role
0 Continental Perlin 0.000001 3 Land/ocean distribution and mountain mask
1 Ridged Ridged Multi 0.000005 3 Mountain ridges and peaks
2 Mountains Simplex 0.010000 1 Mid-frequency mountain detail
3 Ridges Perlin 0.000180 2 Fine ridge detail (disabled by default)

WorldGen | Beach

Property Default Description
Beach Width 0.04 Normalized height band above sea level treated as beach. 0.04 = 4% of height range.
Beach Flatten Strength 0.85 How flat the beach zone becomes. 1.0 = perfectly flat sand.

WorldGen | Water

Property Default Description
Enable Water Plane true Flat water surface at sea level.
Water Material null Material for the water plane.
Water Update Interval (s) 2.0 How often the plane repositions to follow the player.

WorldGen | Far Terrain

Property Default Description
Enable Far Terrain true Low-res LOD ring beyond the near grid.
Far Tile Multiplier 4 Each far tile covers 4×4 near tiles.
Far View Distance (tiles) 3 Far tile ring radius. 3 = 7×7 far tile grid.
Far Tile Resolution 8 Vertices per side on far tiles. 8 is sufficient at that range.

WorldGen | Roads

Property Default Description
Enable Roads false Generate a road network at BeginPlay and expand into newly discovered chunks.
Road Half Width (cm) 800 Corridor radius. Terrain flattened within this distance of road centerline.
Road Flatten Strength 0.90 How aggressively terrain flattens to road height.
Max Settlement Nodes 6 Number of flat sites found and connected.
Search Radius (chunks) 6 World radius scanned for settlement candidates.
Max Settlement Slope (deg) 20 Terrain steeper than this is rejected as a settlement site.
Road Z Offset (cm) 10 Height the road mesh floats above terrain.
Path Slope Sensitivity 5.0 How strongly A* routing avoids slopes. Higher = roads follow valleys more aggressively.
Path Cell Size (tile fraction) 0.25 A* grid resolution. Smaller = finer paths, slower generation.
Road Mesh null Static mesh per road segment (optional).
Road Material null Material for road mesh.

WorldGen | Foliage

Property Default Description
Enable Foliage true Master toggle. Disable for fast terrain iteration.
Foliage Assets empty Array of UBiomeFoliageAsset — one per biome.

WorldGen | Grass (V1.1)

Property Default Description
Enable Grass true Master toggle for the dense grass system. Disable for faster iteration.
Grass Assets empty Array of UWorldGenGrassAsset — one per grass type.

WorldGen | Erosion (V1.2)

Property Default Description
Enable Erosion false Apply hydraulic erosion to terrain heightmaps. Runs fully on the background thread. Note (V1.6): Erosion is automatically disabled at resolution ≤32 to prevent artifacts.
Droplets 4,000 Water droplets simulated per chunk. More = more detail, longer build time.
Erosion Strength 0.3 How aggressively droplets erode terrain. Higher = deeper channels.
Deposition Rate 0.3 How quickly droplets deposit sediment when slowing down. Higher = more valley fill.
Evaporation Rate 0.05 Rate at which droplet water evaporates each step. Higher = shorter, more localised erosion paths.
Sediment Capacity 4.0 Maximum sediment a droplet can carry per unit of speed and water. Higher = deeper valleys.
Inertia 0.05 Momentum factor. 0 = pure gradient descent (sharp channels). 0.05–0.1 = natural meandering.
Brush Radius 3 Erosion/deposition brush radius in vertices. Larger = smoother spread.

What’s Fixed in V1.6

Texture Stretching at Extreme Distance

Problem: Diagonal checkerboard stretching pattern visible on terrain at extreme world distances (starting ~850K units away).

Root Cause: UV coordinates calculated using absolute world coordinates. At 2M+ units, single-precision floats lose precision in division operations, causing uneven texture sampling.

Solution: Use local coordinates (relative to chunk origin) for UV calculation.

Before:

const float WorldX = OriginX + (X * Step - Half);
UVs[I] = FVector2D(WorldX / TextureScale, WorldY / TextureScale);
// Precision loss at extreme distances

After:

const float LocalX = X * Step - Half;
UVs[I] = FVector2D(LocalX / TextureScale, LocalY / TextureScale);
// High precision with small numbers

File: Plugins/WorldGen/Source/WorldGen/Private/WorldChunk.cpp (lines 385–396)

Video Tutorial: See TextureStretching_FloatingPointPrecision_Script.md for a complete 14-minute debug walkthrough with visual aids.


Dynamic Road Expansion (V1.6)

Problem: Roads only appeared in chunks present at BeginPlay. New chunks discovered during gameplay had no roads.

Solution: Implemented ARoadNetwork::ExpandRoadsForChunk() to automatically:

  1. Scan newly loaded chunks for settlement candidates

  2. Pathfind new roads to the existing road network

  3. Skip expensive spline rebuilding (performance optimized)

Result: Roads now generate deterministically across the entire world as the player explores.

Files Modified:

  • RoadNetwork.cpp/h — new ExpandRoadsForChunk() method

  • WorldStreamingManager.cpp — calls ExpandRoadsForChunk() when chunks are acquired


Erosion Safety (V1.6)

Problem: At resolution 32 and below, erosion simulation creates visible artifacts and random terrain spikes.

Solution: Automatically disable erosion when chunk resolution ≤ 32.

File: WorldChunk.cpp (line 192)

if (Erosion.bEnabled && Erosion.Droplets > 0 && Res > 32)
{
    // Erosion is disabled for resolution <= 32 because the output artifacts become unacceptable.
    // ... erosion simulation ...
}

Recommendation: Use LOD array [256, 256, 128, 64] to avoid problematic low resolutions.


Terrain Deformation (V1.4)

WorldGen supports real-time terrain deformation via spherical brushes. Deformation is sculpted with height deltas that persist across chunk rebuilds and are compatible with all LOD resolutions.

Deformation API

Sculpt terrain:

AWorldStreamingManager::DeformTerrain(
    FVector WorldPosition,    // Center of deformation sphere
    float Radius,             // Sphere radius in cm
    float Strength,           // Height delta to apply (-1.0 to 1.0)
    float Falloff             // Gradient softness (0–1). 1.0 = hard edge, 0.0 = smooth fade
)

Remove all deformation:

AWorldStreamingManager::ClearDeformation()

Usage Example

// Raise terrain under the player by 500 cm with a 2000 cm radius
ManagerRef->DeformTerrain(PlayerPos, 2000, 5.0f, 0.8f);

// Lower terrain (negative strength) with hard edge
ManagerRef->DeformTerrain(PlayerPos, 500, -3.0f, 1.0f);

// Reset deformation
ManagerRef->ClearDeformation();

Deformation Notes

  • Deformation applies to all active chunks within the sphere radius.

  • Height deltas are stored per-chunk and persist across terrain reloads and parameter changes.

  • Deformation quality depends on chunk resolution — use higher LOD resolutions near the player for finer detail.

  • Currently terrain deformation is experimental — expect polish in future versions.


Foliage Setup

Creating a Biome Foliage Asset

  1. In Content Browser: Add > Miscellaneous > Data Asset > BiomeFoliageAsset.

  2. Set Biome to the terrain zone this asset covers (Grass, Rock, Snow, or Beach).

  3. Add entries in the Entries array — one per foliage mesh.

  4. Assign the asset to WorldGen > Foliage Assets on the streaming manager.

FFoliageEntry Properties

Property Default Description
Mesh null Static mesh to scatter.
Density 0.002 Instances per m². 0.002 ≈ 1 per 500 m².
Min/Max Normalized Height 0–1 Height range [0–1] where this entry appears.
Min/Max Slope Degrees 0–30 Slope range where this entry spawns.
Vertical Offset (cm) 0 Z offset after terrain snap. Negative = sink into ground.
Position Jitter (cm) 0 Extra random XY displacement per instance.
Scale Range 0.8–1.2 Random uniform scale min/max.
Seed Offset 0 Unique scatter pattern per entry.
View Distance (chunks) 2 Chunk radius within which this entry spawns. Trees: 3–4. Clutter: 1.
Grow in Shade false Allow spawning alongside other foliage. Enable for ground cover under trees.
Enable Collision false Enable collision on instances. Leave off for decorative props — only enable when the player needs to physically interact with this mesh.

Clustering

Property Default Description
Enable Clustering false Clump instances around random centers. Natural for trees, shrubs, rock formations.
Cluster Count 6 Centers per chunk.
Cluster Radius (cm) 5,000 Instances beyond this radius from any center won’t spawn.
Cluster Falloff 2.0 Density drop-off from center to edge. 2 = smooth quadratic.

Recommended Foliage Asset Setup

Asset Biome Typical Entries
DA_Foliage_Grass Grass Large trees (density 0.001, View Distance 4), shrubs (density 0.003, View Distance 2), grass tufts (density 0.01, View Distance 1, Grow in Shade ✓)
DA_Foliage_Rock Rock Rock formations (density 0.002, clustering), cliff moss
DA_Foliage_Snow Snow Dead trees, snow-covered rocks
DA_Foliage_Beach Beach Driftwood, sea grass, shells

Dense Grass System (V1.1)

The dense grass system is a separate scatter layer from the foliage system. It uses a world-snapped ISM grid that moves with the player, giving density that is independent of terrain tile size. This allows hundreds of grass blades per square meter without being limited by chunk vertex count.

Creating a Grass Asset

  1. In Content Browser: Add > Miscellaneous > Data Asset > WorldGenGrassAsset.

  2. Assign a low-poly grass blade mesh to Mesh.

  3. Set Biome to the terrain type where this grass should appear.

  4. Assign the asset to WorldGen > Grass Assets on the streaming manager.

Create one asset per grass type (e.g. green grass, dry grass, flowers, pebbles). Each asset spawns on its own independent grid and ISM component.

UWorldGenGrassAsset Properties

Property Default Description
Biome Grass Terrain type this grass appears on (Grass, Rock, Snow, Beach).
Mesh null Static mesh to scatter. Use low-poly blade cards for best performance.
Density 0.8 Spawn probability per grid cell (0–1). 1.0 fills every grid point.
Min/Max Slope Degrees 0–25 Grass won’t spawn outside this slope range. 25° keeps grass off cliff faces.
Scale Range 0.8–1.2 Random scale per instance.
Vertical Offset (cm) 0 Z offset after terrain snap. Use small negative values to hide blade bases.
Align to Normal true Rotate blades to be perpendicular to the terrain surface rather than straight up.
Slope Sink Depth (cm) 30 Auto-sinks blades into terrain on slopes (proportional to sin of slope angle). Prevents floating on angled surfaces when Align to Normal is on.
Enable Collision false Enable collision on grass instances. Almost never needed — leave off.
Grass Resolution 128 Scatter grid points per axis. 128 = up to 16,384 grid points within the radius.
Grass Radius (cm) 10,000 Radius around the player within which this grass spawns. 10,000 cm = 100 m.

Grass System Tips

  • Keep Grass Radius small (10,000–20,000 cm). A 20 m radius at 128 resolution produces dense coverage without overwhelming the ISM.

  • Slope Sink Depth 10–30 cm prevents the most common floating blade issue on angled terrain. Pair with Align to Normal for best results.

  • Use 2–3 grass assets with different meshes (short, tall, wide) and offset seeds for natural variation.

  • Grass does not need collision — leave Enable Collision off on all grass assets.


Hydraulic Erosion (V1.2)

WorldGen’s erosion system simulates water droplets flowing down terrain slopes, picking up sediment and depositing it in valleys. This runs entirely on background threads — enabling erosion adds zero game-thread cost.

What it produces:

  • Carved river valleys following natural drainage paths

  • Sharp ridge erosion on mountain peaks

  • Sediment fans and alluvial deposits in flat areas

  • Smoother transitions between terrain features

To enable: Check WorldGen > Enable Erosion on the streaming manager and click Preview Terrain.

Note (V1.6): Erosion is automatically disabled at resolution ≤ 32 to prevent artifacts. Use LOD array [256, 256, 128, 64] for best results.

Tuning Guide

Goal Parameters to adjust
More dramatic valleys Raise Erosion Strength, raise Sediment Capacity
Smoother, wider erosion Raise Brush Radius (3–5), lower Erosion Strength
Longer river channels Lower Evaporation Rate (0.01–0.03)
More sediment fans Raise Deposition Rate (0.5–0.7)
Natural meandering Inertia 0.05–0.1; higher = less wandering
Faster preview iteration Lower Droplets to 1,000–2,000 for rough preview; raise to 8,000+ for final quality

Erosion Performance Notes

  • Erosion runs on the background thread alongside mesh building — no game-thread cost.

  • Build time scales linearly with Droplets. 4,000 droplets at Resolution 64 adds ~5–10ms per chunk on a modern CPU.

  • Erosion does not affect collision accuracy — it modifies the heightmap before mesh and collision are built.


Multiplayer (V1.3)

WorldGen supports both listen server and dedicated server multiplayer out of the box. No additional setup is required — place one WorldStreamingManager in your level as usual.

How It Works

Listen server / host:

  • The server player’s origin is detected via GetStreamingOrigins().

  • Terrain streams around all connected players simultaneously.

  • Each player’s chunk position is tracked independently — a chunk loads if any player is within range.

Clients:

  • Each client runs its own WorldStreamingManager instance.

  • On clients, GetStreamingOrigins() returns only the local player’s position, keeping each client responsible for its own terrain.

Dedicated server:

  • Terrain is built for all connected players.

  • The dedicated server skips all visual mesh data, foliage, and grass — it builds collision geometry only.

  • This keeps server memory and CPU cost minimal while ensuring accurate physics for all players.

Per-Player Gravity Delay

The Terrain Load Delay setting is applied per-player, including late joiners. When a new player connects, gravity is suspended for that controller for the delay duration, then restored. This prevents falling through terrain before async collision finishes cooking.

Increase Terrain Load Delay if players occasionally fall through terrain on first spawn.

Multiplayer Setup Checklist

  • Place one WorldStreamingManager in your level — no duplication needed.

  • Ensure your Game Mode is compatible with the number of players you expect.

  • If using a dedicated server, enable server support in your project packaging settings.

  • Do not set bNetLoadOnClient = false on the streaming manager — this prevents clients from running their own terrain instance.


Performance Guide

Recommended Settings by Target

Target Resolution View Distance LOD Array Far Terrain Foliage Grass
High-end PC 64–96 5–6 [256,256,128,64] On, FarVD 4 Full Radius 20,000, Res 256
Mid-range PC 64 4 [256,256,128,64] On, FarVD 3 View Distance 2 max Radius 10,000, Res 128
Low-end / Console 32–48 3 [128,128,64,64] On, FarVD 2 View Distance 1 only Radius 5,000, Res 64

Note (V1.6): Avoid resolution 32 in LOD array due to erosion artifacts. Minimum recommended is 64.

Key Performance Notes

  • Resolution is the biggest single cost. Going from 64 to 128 quadruples geometry per chunk.

  • Foliage View Distance drives HISM instance count. Keep large trees at 3–4, dense ground clutter at 1.

  • Enable Foliage = false during parameter tuning — rebuilds are 10× faster.

  • AddInstances runs on the game thread. Keep per-biome instance counts below ~15,000 per chunk.

  • Async collision is enabled by default. Do not disable it — it prevents game thread hitches on chunk load.

  • Grass Radius is the primary grass cost lever. Halving the radius quarters the instance count.

  • Erosion adds build time per chunk proportional to Droplets but zero game-thread cost. 4,000 droplets is a good production default.

  • Dedicated servers skip all visual and foliage work — server memory scales only with collision geometry and connected player count.


Known Limitations (V1.6)

  • Dense grass not supported via HISM at extreme density. Keep Grass Radius reasonable (≤ 20,000 cm). Full GPU grass is a V2.0 feature.

  • Terrain deformation is experimental. The feature is functional but may receive optimizations and UI polish in future releases.

  • Landscape Grass Tool incompatible. WorldGen uses ProceduralMeshComponent, not UE’s Landscape — native Landscape Grass does not work.

  • Slope estimation in SampleHeight() uses Layer 0 only — cheap approximation, not a full gradient.

  • No runtime parameter changes. Changing noise layers, tile size, or LOD array at runtime requires calling PreviewTerrain() or triggering a full terrain rebuild.

  • Material required. WorldGen provides vertex data only — you must build the terrain material yourself using the channel reference above.

  • Erosion is deterministic per-seed but not seamlessly continuous across chunks. Each chunk is eroded independently — very wide river channels near chunk borders may not fully connect. This is a known architectural tradeoff of chunk-based streaming.

  • Multiplayer: all players must have the same terrain parameters. WorldStreamingManager is not replicated — clients generate terrain independently using the same seed and settings. If parameters differ between client and server builds, terrain will not match.

  • Erosion disabled at resolution ≤ 32. Low resolutions produce unacceptable artifacts. Use resolution ≥ 64.


FAQ

Q: My terrain has no foliage. A: Check that your BiomeFoliageAsset has meshes assigned, the asset is in the Foliage Assets array, and Enable Foliage is on. Also verify Rock Start is above Sea Level — if Rock Start ≤ Sea Level the grass zone disappears.

Q: I see green (grass) bleeding through the beach or underwater. A: Set up the underwater mask using AbsoluteWorldPosition (see Material Setup above). The vertex color R channel alone causes interpolation artifacts on slopes crossing the waterline.

Q: Chunk seams are visible. A: This is usually the material, not the geometry. The mesh normals are seamless by design (1-vertex border overlap). Check that your material is not using an unsmoothed normal map.

Q: Preview Terrain is slow. A: Disable foliage (Enable Foliage = false) and reduce View Distance to 2 while iterating on noise parameters.

Q: Road splines stay visible after I disable roads. A: Click Clear Terrain — this also clears any existing road splines.

Q: Can I use this in a shipped game? A: Yes. FastNoise Lite (MIT licensed) is included in the plugin source. The license ships with purchasers automatically since the file is in the plugin tree.

Q: My grass blades are floating above the terrain on slopes. A: Enable Align to Normal on the grass asset and increase Slope Sink Depth (10–30 cm). The sink depth is proportional to the sine of the slope angle, so it automatically scales with steepness.

Q: Grass only appears near the player’s starting position. A: Check that Enable Grass is on and Grass Assets is populated. Also verify the Biome on each grass asset matches the terrain type at your spawn location — if Rock Start is too low, the spawn area may be rock-classified and grass assets with Biome = Grass won’t fire.

Q: Enabling erosion causes terrain spikes or broken geometry. A: This usually means the heightmap contains un-normalized values. Enable erosion only after verifying the default noise settings produce smooth terrain. Erosion operates on normalized [0–1] heights — extreme height scale values can produce instability. Try reducing Erosion Strength to 0.1 and Droplets to 1,000 first to confirm the effect before increasing.

Q: Erosion makes every chunk look the same — no variation. A: Erosion is seeded per chunk using the master seed, so each chunk erodes differently. If results look repetitive, the terrain may be too uniform before erosion. Add more noise layer variation or increase WarpStrength to create more distinct starting shapes.

Q: In multiplayer, my client player falls through the terrain. A: Increase Terrain Load Delay on the streaming manager. The delay is applied per-player and suspends gravity while async collision cooks. 4–6 seconds is usually sufficient; if players still fall through, increase further.

Q: On a dedicated server, terrain generates but I see no foliage or grass. A: This is intentional. Dedicated servers build collision-only geometry and skip all visual and foliage work to minimise server cost. Only clients receive foliage and visual meshes.

Q: Two players see different terrain. A: Ensure both builds (client and server) use identical WorldStreamingManager settings, especially Seed, TileSize, Resolution, and all noise parameters. Any difference in noise configuration will produce different terrain heights.

Q: What is LOD and how do I use it? A: LOD (Level of Detail) allows different terrain chunks to be built at different resolutions based on distance from the player. By default (V1.6), the player’s chunk is 256 vertices/side, adjacent chunks are 256, one ring out is 128, and distant chunks are 64. This keeps deformation quality high near the player without burning memory on distant terrain. Disable Enable LOD to revert to flat Resolution for all chunks.

Q: How do I change LOD resolutions? A: Edit the LOD Resolutions array on the streaming manager. Index 0 is the player’s chunk (Chebyshev distance 0), index 1 is one ring out (distance 1), etc. The last entry is reused for all further rings. For V1.6, the default [256, 256, 128, 64] is recommended — it avoids resolution 32 artifacts.

Q: I’m getting poor deformation quality. A: Deformation quality depends on chunk resolution. Enable LOD and set higher resolutions in the LOD Resolutions array for chunks near the player (e.g., [256, 128, 64] instead of [128, 128, 64]). Brush deformation on 256-resolution terrain is much finer than on 64-resolution terrain.

Q: Can I blend deformation with erosion? A: Yes. Deformation applies height deltas after erosion is evaluated. You can sculpt eroded terrain and the deltas persist through chunk reloads. Enable both Enable Erosion and sculpt with DeformTerrain() for combined effect.

Q: Deformation is slow or hitchy. A: Deformation rebuilds affected chunks immediately. If you’re deforming many chunks at once, space out DeformTerrain() calls across multiple frames or reduce the Strength to affect fewer chunks. Currently deformation is experimental — expect optimization in future versions.

Q: Texture stretching at extreme distance — is it fixed? A: Yes (V1.6). The fix changes UV calculation from world coordinates to local coordinates. This eliminates floating-point precision loss and the diagonal stretching pattern at 2M+ units. See BugFixes.md and the video tutorial for technical details.

Q: Why are roads not appearing in newly discovered chunks? A: If you’re on V1.5 or earlier, upgrade to V1.6. V1.6 adds ExpandRoadsForChunk() which automatically generates roads in newly loaded chunks as the player explores. The system is now complete and deterministic across the entire world.


Roadmap

Completed

Version Date Feature
V1.0 2025 Infinite chunk streaming, layered noise, biome blending, water, beach, HISM foliage
V1.1 2026 Dense ISM grass system with world-snapped radius grid, per-asset resolution/radius, slope sink
V1.2 2026 Hydraulic erosion (particle droplet simulation, fully async, border-safe)
V1.3 2026 Multiplayer support — multi-origin streaming, dedicated server collision-only mode, per-player gravity delay
V1.4 2026 Terrain deformation (experimental), fixed texture world scale, fixed foliage grid placement
V1.5 2026 Distance-based LOD system with configurable per-ring resolutions, seamless transitions, increased resolution support up to 256+
V1.6 2026 Texture stretching fix, dynamic road expansion, erosion safeguard, LOD optimization

V1.7 — Editor Tooling (Planned)

  • Visual noise layer editor in the WorldGenEditor module

  • Biome map preview texture rendered in-editor

  • Better far terrain seam handling at horizon

V2.0 — PCG Grass & Production Roads (Planned)

  • PCG integration for GPU-side grass scatter

  • Expose chunk heightmap data to a PCG graph

  • Native UE5 frustum and distance culling for grass blades at full density

  • Production-quality road network (A* terrain-following, corridor foliage removal, bridges/tunnels)

V2.1 — PCG Biomes (Planned)

  • PCG-driven biome distribution with temperature and humidity maps

  • River system

  • Settlement system with road-connected villages


Credits

Plugin: CodeLikeMe
Noise Library: FastNoise Lite by Jordan Peck / Auburn (MIT License)
Engine: Unreal Engine 5.4 by Epic Games


Want to Build It Yourself?

The full system was built from scratch and documented step-by-step on the CodeLikeMe channel as the WorldEngine — Runtime Infinite Terrain Generator tutorial series. Every system in this plugin — the chunk pool, the noise stack, the foliage scatter — is covered in detail.

Tutorial series: https://www.youtube.com/playlist?list=PLNTm9yU0zou6B6eqrPrRjODBd2OD-BVsh

The plugin is for developers who want to skip straight to shipping. The series is for developers who want to understand every line.