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
-
Copy the WorldGen folder into your project’s Plugins/ directory.
-
Right-click your .uproject and choose Generate Visual Studio project files.
-
Open the solution, build, and launch the editor.
-
The plugin is automatically enabled — no manual activation needed.
Quick Start
1. Place the streaming manager
2. Assign a terrain material
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
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:
-
Scan newly loaded chunks for settlement candidates
-
Pathfind new roads to the existing road network
-
Skip expensive spline rebuilding (performance optimized)
Result: Roads now generate deterministically across the entire world as the player explores.
Files Modified:
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
-
In Content Browser: Add > Miscellaneous > Data Asset > BiomeFoliageAsset.
-
Set Biome to the terrain zone this asset covers (Grass, Rock, Snow, or Beach).
-
Add entries in the Entries array — one per foliage mesh.
-
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
-
In Content Browser: Add > Miscellaneous > Data Asset > WorldGenGrassAsset.
-
Assign a low-poly grass blade mesh to Mesh.
-
Set Biome to the terrain type where this grass should appear.
-
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)
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.