Introduction
TerraDyne is a next-generation native plugin for Unreal Engine 5.7. It decouples landscape physics from visual representation, enabling infinite runtime deformation — digging, raising, and painting — with fully persistent state, distance-based scalability, and smart procedural visuals.
The Scaling Problem
Legacy voxel systems are CPU heavy. Standard landscapes are static. Runtime mesh manipulation often leads to collision desyncs and visual seams.
TerraDyne solves this via Synchronous Physics / Asynchronous Visuals. We use a CPU-side float cache to drive throttled collision updates (Geometry Script) while simultaneously pushing R16f textures to the GPU for Virtual Heightfield Mesh displacement.
Technical Pillars
Built strictly for UE 5.7, TerraDyne leverages modern modules like Geometry Scripting and Virtual Texturing to achieve AAA performance.
Direct Memory Write
Bypasses slow material draws using low-level memory locking (`LOCK_READ_WRITE`) to push float arrays directly to R16f textures.
Smart Procedurality
Includes a "Smart Material" pipeline that automatically textures terrain based on Slope (Rock/Grass) and Height (Snow/Sand) without manual painting.
Adaptive Scalability
Chunks utilize distance-based LOD to disable physics >500m away, and edits are debounced (0.2s) to prevent frame spikes during rapid sculpting.
Quick Start Guide (Developers)
1. Include the Module
TerraDyne relies on core geometry modules. Ensure your Build.cs includes:
PublicDependencyModuleNames.AddRange(new string[] {
"TerraDyne", "GeometryScripting", "VirtualHeightfieldMesh"
});
2. Access the Manager
The ATerraDyneManager is a singleton-style actor registered to the world subsystem. You do not need to scan for it.
// Get the Subsystem first
if (UTerraDyneSubsystem* Sys = GetWorld()->GetSubsystem())
{
// Retrieve the active Manager
if (ATerraDyneManager* Manager = Sys->GetTerrainManager())
{
// 3. Dig a hole (Radius 500, Strength -100)
Manager->ApplyGlobalBrush(HitLocation, 500.0f, -100.0f, false);
// 4. Save Changes
Manager->SaveWorld("MySaveSlot");
}
}
3. Configure a Projectile
For fast-moving objects (meteors, grenades) to interact with dynamic terrain, enable CCD and bind to the Hit event.
MeshComp->BodyInstance.bUseCCD = true; // Prevents Tunneling
MeshComp->OnComponentHit.AddDynamic(this, &ATerraDyneProjectile::OnHit);
Configuration
TerraDyne exposes global settings via the Unreal Editor's Project Settings window. This allows you to configure default materials, asset paths, and performance thresholds without recompiling C++.
Configuration Data Flow
Asset Paths
-
Master Material Path
Defines the default material applied to new chunks.
Default: /Game/TerraDyne/Materials/VHFM/M_TerraDyne_Smart - Height Brush Material The "Stamp" texture used for sculpting.
- HUD Widget Class The UI widget spawned by the Showcase Orchestrator.
Performance Tuning
-
LOD Distance Threshold
float
Distance (in cm) at which chunks disable complex collision. Default is 50,000 (500m). -
Collision Debounce Time
seconds
Wait time after a brush stroke before triggering a physics cook. Increase for smoother sculpting, decrease for responsiveness.
Using TerraDyne
This guide covers the operational workflows for TerraDyne: setting up the Manager, importing worlds via Lidar, and utilizing the runtime brush API for gameplay mechanics.
1 Manager Configuration
The BP_TerraDyneManager is the central orchestrator. It must be placed in the level (usually at 0,0,0) to manage chunk streaming and tool distribution.
Required Property Assignments
- Chunk Class:
BP_TerraDyneChunk(The tile actor) - Master Material:
M_TerraDyne_Smart(Procedural) - Height Brush Material:
M_HeightBrush(Additive Shape) - Weight Brush Material:
M_WeightBrush(Layer Masking)
2 Runtime Brush API
Use ApplyGlobalBrush to deform terrain or paint layers. The system automatically debounces collision updates (0.2s delay) to ensure smooth frame rates during continuous painting.
// 1. Sculpting (Physics)
Deforms geometry. Physics updates automatically via Async Cook.
Manager->ApplyGlobalBrush(
HitLocation, // Center
500.0f, // Radius
-50.0f, // Strength (Neg=Dig)
false, // bIsHole
-1 // Layer (-1 = Sculpt)
);
// 2. Painting (Visuals)
Updates RGBA Weightmap. Does not affect collision.
Manager->ApplyGlobalBrush(
HitLocation,
500.0f, // Radius
1.0f, // Opacity
false,
1 // Layer ID (0=R, 1=G...)
);
3 Persistence (Save/Load)
TerraDyne 1.1 introduces a full serialization pipeline. You can capture the state of every chunk (Height & Layers) and save it to disk using the standard USaveGame framework.
Saving the World
Manager->SaveWorld("Level1_State");
Serializes all ActiveChunkMap entries into compressed float arrays. The file is stored in Saved/SaveGames/.
Loading the World
Manager->LoadWorld("Level1_State");
Restores terrain state. Missing chunks are automatically spawned. Existing chunks are updated in-place.
Technical Reference (C++)
This section details the internal architecture, class hierarchy, and low-level data flow of the TerraDyne Runtime module.
ATerraDyneManager
Singleton-like actor responsible for routing "Brush" events to the correct world grid cells.
| Function Signature | Description |
|---|---|
| ApplyGlobalBrush(...) |
Calculates which grid cells overlap the brush radius and forwards the call.
Params: Location, Radius, Strength, bIsHole, PaintLayer |
| SaveWorld(SlotName) |
Serializes the entire world state to disk using UTerraDyneSaveGame.
|
| LoadWorld(SlotName) | Deserializes and restores world state. Spawns chunks if they don't exist. |
| RebuildChunkMap() |
Scans the world for ATerraDyneChunk actors and rebuilds the spatial hash.
|
ATerraDyneChunk
The atomic unit of terrain. Handles the sync between CPU float arrays, GPU textures, and Physics collision.
| Variable / Function | Description |
|---|---|
| TArray<float> HeightBuffer | The "Source of Truth". A simple 1D float array representing the Z-height of every vertex in the grid. |
| UpdateLOD(ViewerPos) |
Checks distance to viewer. If > 500m, sets collision to NoCollision to save CPU.
|
| GetSerializedData() | Packs the chunk's coordinates, ZScale, and HeightBuffer into a struct for saving. |
Threading & Performance Model
Physics (Async Cook)
TerraDyne sets PhysicsMesh->UpdateCollision(true). This pushes the PhysX/Chaos geometry cooking to a background thread.
Visuals (RHI Command)
Texture updates use ENQUEUE_RENDER_COMMAND (implicit via UpdateResource) to upload float data. This avoids Game Thread stalls during frame rendering.
Chunk System & LOD
TerraDyne employs an intelligent Level of Detail (LOD) system to maintain high performance even in massive worlds.
Distance-Based Activation
Near Field (< 500m)
Chunks have Complex Collision enabled. Projectiles bounce, characters can walk, and edits trigger immediate physics recooks (debounced).
Far Field (> 500m)
Chunks automatically switch to NoCollision. They remain visible via VHFM but consume zero physics time. This allows for essentially infinite visual horizons.
Troubleshooting Guide
The Cure
This is intended behavior (optimization). If you need physics further out (e.g., for sniping), adjust the threshold in ATerraDyneChunk::UpdateLOD or TerraDyneManager.cpp.
The Cure
Physics updates are delayed by 0.2s to prevent frame drops. This is a trade-off for performance. For "instant" feedback, you would need to accept significant FPS loss on complex meshes.
The Cure
1. Material Check: Ensure M_TerraDyne_Smart is assigned in Project Settings. If assets were missing on boot, restart the Editor.
2. Render Target: The GPU readback requires RTF_RGBA16f (FloatRGBA). Check your log for "Invalid Format" warnings.
3. Flush: Ensure FlushRenderingCommands() is called before readback (handled automatically in v1.2+).
The Cure
The Virtual Heightfield Mesh (Visuals) and Dynamic Mesh (Physics) must have identical Z-Scaling. In v1.2+, this is enforced to 1.0. If you see this, check if your Chunk BP has a manual Z-Scale override.
GregOrigin
Created by Andras Gregori @ Gregorigin, a single dad currently based outside Budapest, HU.
"Building tools that empower creators to shape worlds."