Ue Procedural Generation
Use this skill when working with procedural generation in Unreal Engine: PCG framework, ProceduralMesh, instanced mesh, HISM, spline, runtime mesh, noise, terrain generation, or dungeon generation. See references/pcg-node-reference.md for PCG node types and references/procedural-mesh-patterns.md for mesh generation patterns. For physics on procedural geometry, see ue-physics-collision.
- Skill ID
- quodsoler/unreal-engine-skills/ue-procedural-generation
- Publisher
- quodsoler
- Repository
- unreal-engine-skills
- Installs
- 0
- Files
- 3
- Synced
- Sep 23, 2026
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
quodsoler/unreal-engine-skills/ue-procedural-generationInstalls these files- SKILL.md
- references/pcg-node-reference.md
- references/procedural-mesh-patterns.md
What this skill tells the agent
ue-procedural-generation
You are an expert in Unreal Engine's procedural generation systems, including the PCG framework, ProceduralMeshComponent, instanced static meshes, noise functions, and spline-based generation.
Context Check
Before advising, read .agents/ue-project-context.md to determine:
- Whether the PCG plugin is enabled (plugins list)
- Target generation type: world layout, terrain, dungeon, vegetation, runtime mesh
- Performance constraints (mobile, console, Nanite enabled)
- Multiplayer requirements (server authority vs. deterministic seeding)
Information Gathering
Ask for clarification on:
- Generation type: world population (PCG), runtime mesh (ProceduralMeshComponent), instanced geometry (ISM/HISM), or spline-driven?
- Timing: editor-time baked result or runtime dynamic generation?
- Instance count: hundreds (ISM) or tens of thousands (HISM)?
- Collision: does generated geometry need physics collision?
- Determinism: same seed must produce same result across sessions or network clients?
1. PCG Framework (UE 5.2+)
Node-based rule-driven world generation. Operates on point clouds with transform, density, color, seed, and metadata attributes.
Plugin Setup
// Build.cs
PublicDependencyModuleNames.Add("PCG");// .uproject Plugins array
{ "Name": "PCG", "Enabled": true }Core Classes
| Class | Header | Purpose |
|---|---|---|
UPCGComponent | PCGComponent.h | Actor component driving generation |
UPCGGraph | PCGGraph.h | Asset: nodes + edges |
UPCGGraphInstance | PCGGraph.h | Graph instance with parameter overrides |
UPCGPointData | Data/PCGPointData.h | Point cloud between nodes |
UPCGSettings | PCGSettings.h | Node settings base class |
UPCGBlueprintBaseElement | Elements/Blueprint/PCGBlueprintBaseElement.h | Custom Blueprint node base |
UPCGComponent Key API (from PCGComponent.h)
// Assign graph (NetMulticast)
void SetGraph(UPCGGraphInterface* InGraph);
// Trigger generation (NetMulticast, Reliable) — use for multiplayer
void Generate(bool bForce);
// Local non-replicated generation
void GenerateLocal(bool bForce);
// Cleanup
void Cleanup(bool bRemoveComponents);
void CleanupLocal(bool bRemoveComponents);
// Notify to re-evaluate after Blueprint property change
void NotifyPropertiesChangedFromBlueprint();
// Read generated output
const FPCGDataCollection& GetGeneratedGraphOutput() const;Generation triggers (EPCGComponentGenerationTrigger):
GenerateOnLoad— one-shot on BeginPlayGenerateOnDemand— explicitGenerate()call onlyGenerateAtRuntime— budget-scheduled byUPCGSubsystem
UPCGGraph Node API (from PCGGraph.h)
// Add node by settings class
UPCGNode* AddNodeOfType(TSubclassOf<UPCGSettings> InSettingsClass, UPCGSettings*& DefaultNodeSettings);
// Connect two nodes
UPCGNode* AddEdge(UPCGNode* From, const FName& FromPinLabel, UPCGNode* To, const FName& ToPinLabel);
// Graph parameters (typed template)
template<typename T>
TValueOrError<T, EPropertyBagResult> GetGraphParameter(const FName PropertyName) const;
template<typename T>
EPropertyBagResult SetGraphParameter(const FName PropertyName, const T& Value);Custom Blueprint PCG Node
Derive from UPCGBlueprintBaseElement:
UCLASS(BlueprintType, Blueprintable)
class UMyPCGNode : public UPCGBlueprintBaseElement
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "PCG|Execution")
void Execute(const FPCGDataCollection& Input, FPCGDataCollection& Output);
};
// In Execute:
FRandomStream Stream = GetRandomStreamWithContext(GetContextHandle()); // deterministic seed
for (const FPCGTaggedData& In : Input.GetInputsByPin(PCGPinConstants::DefaultInputLabel))
{
const UPCGPointData* InPts = Cast<UPCGPointData>(In.Data);
if (!InPts) continue;
UPCGPointData* OutPts = NewObject<UPCGPointData>();
for (const FPCGPoint& Pt : InPts->GetPoints())
{
FPCGPoint NewPt = Pt;
NewPt.Density = Stream.FRandRange(0.5f, 1.0f);
OutPts->GetMutablePoints().Add(NewPt);
}
Output.TaggedData.Emplace_GetRef().Data = OutPts;
}Key UPCGBlueprintBaseElement properties:
bIsCacheable = false— when node spawns actors or componentsbRequiresGameThread = true— for actor spawn, component addCustomInputPins/CustomOutputPins— extra typed pins
PCG Determinism
PCG graphs are deterministic by default — the same seed produces identical output. Each node receives a seeded random stream via GetRandomStreamWithContext(). To vary output across instances, set the PCG component's Seed property. For multiplayer, ensure all clients use the same seed (replicate via GameState or pass as spawn parameter).
// Set PCG seed at runtime for deterministic variation
UPCGComponent* PCG = FindComponentByClass<UPCGComponent>();
PCG->Seed = MyDeterministicSeedValue;
PCG->Generate(); // Regenerate with new seedPCG Data Types
| Type | Contains | Use for |
|---|---|---|
FPCGPoint / Point Data | Position, rotation, scale, density, color | Scatter placement, foliage, instance positioning |
UPCGSplineData | Spline points + tangents | Roads, rivers, paths, boundary definitions |
UPCGLandscapeData | Height + layer weight sampling | Terrain-aware placement, biome queries |
UPCGVolumeData | 3D bounds | Volume-based filtering and generation |
Point data is the most common — most PCG nodes consume and produce point collections. Also available: UPCGTextureData, UPCGPrimitiveData, UPCGDynamicMeshData.
See references/pcg-node-reference.md for all node types, settings fields, and pin labels.
2. ProceduralMeshComponent
// Build.cs
PublicDependencyModuleNames.Add("ProceduralMeshComponent");Core API
// Create section: vertices, triangles (CCW = front), normals, UVs, colors, tangents
void CreateMeshSection(int32 SectionIndex,
const TArray<FVector>& Vertices, const TArray<int32>& Triangles,
const TArray<FVector>& Normals, const TArray<FVector2D>& UV0,
const TArray<FColor>& VertexColors, const TArray<FProcMeshTangent>& Tangents,
bool bCreateCollision);
// Updates vertex positions (incl. collision if enabled). Cannot change topology.
void UpdateMeshSection(int32 SectionIndex,
const TArray<FVector>& Vertices, const TArray<FVector>& Normals,
const TArray<FVector2D>& UV0, const TArray<FColor>& VertexColors,
const TArray<FProcMeshTangent>& Tangents);
void ClearMeshSection(int32 SectionIndex);
void ClearAllMeshSections();
void SetMeshSectionVisible(int32 SectionIndex, bool bNewVisibility);
void SetMaterial(int32 ElementIndex, UMaterialInterface* Material);Terrain Grid Example
void ATerrainActor::Build(int32 Grid, float Cell)
{
TArray<FVector> Verts; TArray<int32> Tris; TArray<FVector> Norms;
TArray<FVector2D> UVs; TArray<FColor> Colors; TArray<FProcMeshTangent> Tangs;
for (int32 Y = 0; Y <= Grid; Y++)
for (int32 X = 0; X <= Grid; X++)
{
float Z = SampleOctaveNoise(X * Cell, Y * Cell, 4, 0.5f, 2.f, 80.f);
Verts.Add(FVector(X * Cell, Y * Cell, Z));
Norms.Add(FVector::UpVector);
UVs.Add(FVector2D((float)X / Grid, (float)Y / Grid));
}
for (int32 Y = 0; Y < Grid; Y++)
for (int32 X = 0; X < Grid; X++)
{
int32 BL = Y*(Grid+1)+X, BR=BL+1, TL=BL+(Grid+1), TR=TL+1;
Tris.Add(BL); Tris.Add(TL); Tris.Add(TR);
Tris.Add(BL); Tris.Add(TR); Tris.Add(BR);
}
ProceduralMesh->CreateMeshSection(0, Verts, Tris, Norms,
UVs, Colors, Tangs, /*bCreateCollision=*/true);
}Performance Notes
- One draw call per
CreateMeshSection. Keep vertex count < 65K per section.
More from quodsoler
Use this skill in a project
Open any RiverX project, search the Skills panel for quodsoler/unreal-engine-skills/ue-procedural-generation, and install it in one click.
