CAbstractWorldmaker
Overview
UCAbstractWorldmaker is the abstract base class for terrain generation. It manages the tile grid, LOD computation, async build pipeline, noise blending and mesh lifecycle. Concrete implementations (UCWorldmaker_ProceduralMesh, UCWorldmaker_DynamicMesh) provide the actual mesh creation.
Pure Virtual Functions
| Name |
Description |
| isFirstStart |
Returns true if no mesh has been created yet |
| cleanPmc |
Destroys the mesh component at a given UV index |
| calculatePoint |
Computes tile mesh data (LOD, vertex count, transform) for a world/relative UV pair |
| createPMC_sync |
Creates mesh components on the game thread from pre-calculated data |
| debug |
Toggles debug material on/off for all mesh components |
// These must be implemented by subclasses:
virtual bool isFirstStart() = 0;
virtual void cleanPmc(FCUVIndex index, bool clearContent, bool remove = true) = 0;
virtual void calculatePoint(const FCUVIndex& world, const FCUVIndex& rel) = 0;
virtual void createPMC_sync(const TArray<TPair<FCUVIndex, FCUVIndex>>& pairUVArray, bool poolStart, int poolSize) = 0;
virtual void debug(bool onOff, UMaterialInterface* debugMaterial) = 0;
Build Pipeline
| Name |
Description |
| buildASync |
Entry point called by the spawner. Runs drawFloor async then updatePMC_sync on game thread |
| wantDraw |
Guards against redundant draws: checks room state, pawn movement and queue status |
| drawFloor |
Computes the tile grid around the pawn, runs calculatePoint in parallel, enqueues pooled batches |
| updatePMC_sync |
Dequeues one batch, removes old tiles, calls createPMC_sync, broadcasts delegates |
| adaptPoolSize |
Dynamically adjusts pool batch size based on frame time |
// buildASync is the main entry point, called each tick by ACWorldSpawner:
worldmaker->buildASync(singleDoRun, pawnX, pawnY);
// Internally:
// 1. wantDraw() checks if a new draw pass is needed
// 2. drawFloor() computes UV grid, runs calculatePoint() in ParallelFor
// 3. Results are enqueued as FCWorldDataQueue batches
// 4. updatePMC_sync() dequeues and creates meshes on game thread
Z Calculation & Noise Blending
| Name |
Description |
| innerZCalculate |
Computes the Z height at (x,y) by blending world, cluster, room and edge noises |
| calcMax4PointSlope |
Samples 4 surrounding points to estimate terrain slope |
| calcNormal |
Computes a surface normal from 3 sample points |
| bendRotatorOnSlope |
Adapts a rotator to align with the computed slope |
// innerZCalculate blends multiple noise layers:
// - worldNoise: base terrain noise
// - clusterNoise: per-cluster noise variation (with optional specific noise per cluster)
// - clusterShiftNoise: shift noise for cluster boundaries
// - roomNoise: noise variation inside rooms
// Blending uses easeIt() with the configured easeMethod (default QuinticInOut).
FLinearColor vertexColor;
float z = worldmaker->innerZCalculate(x, y, vertexColor);
// Vertex color encodes spatial context for material use:
// R = cluster proximity (0 = outside, 1 = center)
// G = room proximity (0 = outside, 1 = center)
// B = corridor/edge proximity (0 = outside, 1 = center)
// A = biome noise value (normalized)
Noise Sources
| Name |
Description |
| worldNoise |
Base terrain noise, singleton CNAME_Singleton_WorldNoise |
| biomeNoise |
Biome boundary noise, singleton CNAME_Singleton_BiomeNoise. Stored in vertex color alpha |
| clusterNoise |
Cluster-level noise, singleton CNAME_Singleton_ClusterNoise. Can be overridden per cluster |
| clusterShiftNoise |
Cluster boundary shift noise, singleton CNAME_Singleton_ClusterShiftNoise. Can be overridden per cluster |
| roomNoise |
Room-level noise, singleton CNAME_Singleton_RoomNoise |
State & Delegates
| Name |
Description |
| isReady |
Returns true once noise initialization is complete |
| isBuilt |
Returns true once all tile batches have been processed |
| isRendered |
Checks if a tile at (x,y) is rendered, outputs UV index and full LOD status |
| onTileReady |
Delegate broadcast when a tile mesh is created (with UV index and fullLOD flag) |
| onTileRemoved |
Delegate broadcast when a tile mesh is removed (with UV index and area rectangle) |
// Bind to tile lifecycle events:
worldmaker->onTileReady.AddDynamic(myObject, &ICWorldBoundable::onTileReady);
worldmaker->onTileRemoved.AddDynamic(myObject, &ICWorldBoundable::onTileRemoved);
// Check world state:
if (worldmaker->isReady()) { /* Z queries are safe */ }
if (worldmaker->isBuilt()) { /* all tiles generated */ }
FCUVIndex uvIndex;
bool fullLOD;
if (worldmaker->isRendered(x, y, uvIndex, fullLOD)) {
// tile exists and is rendered
}