After running a path through a forest, you often want to "bend it a bit more to the right". Delete trees near the path and add trees back where it opened up. Tidying placement means repeating that every time you adjust the terrain or path.
PCG is a mechanism for keeping the rules that build placement. Set up "place trees on this ground, but keep steep slopes and the area around the path clear" and you can change the path's shape and regenerate placement by that rule.
This article first gets objects lining up on the ground, then adds "do not place here" conditions. Without tree assets, you can follow the same steps with a box that ships with UE.
What You'll Learn
- The relationship between candidate "points" and the meshes placed on them
- Lining objects up on the ground with a PCG Volume and a graph
- How to remove candidates on steep slopes
- Clearing the area around a curve and rebuilding placement when the path changes
PCG is "make points, then place on them"
PCG (Procedural Content Generation) is a mechanism generating content from procedures and conditions. We use it here to place trees on the ground.
What matters is that what you create first is not trees but candidate points where trees go . Points carry not just position but rotation, scale, and other information. Build candidates, remove points where you do not want placement, and finally place trees on what remains.

You build this procedure by connecting nodes in a PCG graph . A node is a part handling one operation such as "make points" or "remove points". Placement data flows along the wires.
Too many trees, reduce the candidates; want a wider path, widen the exclusion. Instead of fixing placement results one tree at a time, you fix the conditions that decide placement . That is where PCG earns its place.
Choosing against the Foliage tool
Foliage also places trees and grass in bulk with a brush. The difference from PCG is less about count and more about "how the placement location is decided".

| Method | The operation that decides placement | Work it suits |
|---|---|---|
| Foliage | Paint where to place with a brush | Adding roadside grass and rocks while watching the scenery |
| PCG | Graph conditions such as ground, slope, and paths | Rebuilding a forest by the same rules while changing paths and terrain |
You can build the whole forest with PCG and add grass at the entrance with Foliage, for instance. Note, though, that PCG's exclusion conditions do not delete trees or grass you placed by hand separately . Adjust what each method placed individually.
First PCG: line objects up on the ground
From here we work in the editor. Success is boxes or trees lining up on a corner of the Landscape. We handle steep slopes and paths after confirming things line up.
Prepare the ground and the plugin
Open a level with a Landscape. If you have none, build ground and a small hill following the Landscape introduction. We use one corner of the ground at first.
Enable Procedural Content Generation Framework in "Edit → Plugins" and restart the editor if prompted. PCG became Production-Ready in UE5.7. Below we use that generation's basic nodes.
For what to place, you can use a tree Static Mesh you have. A Static Mesh is a 3D model asset such as a tree or rock. Without material, turn on "Show Engine Content" in the Content Browser settings so Engine/BasicShapes/Cube is selectable. Confirm the placement mechanism with boxes and swap in trees later if you like.
Prepare the volume and the graph
A PCG Volume is the Actor (an object placed in the level) enclosing the range this graph places into. Rather than floating above the ground, place it so the ground is inside the box.
- Search for
PCG Volumein "Place Actors", put it in the level, and name itPCG_PracticeVolume. - Scale it so it includes part of the flat ground and part of the hill's slope. A few dozen meters is enough at first. Overlap the ground including in height.
- Right-click in the Content Browser and create
PCG_ForestPracticevia "PCG → PCG Graph". If a template picker appears, start from an empty graph. - Select the level's PCG Volume and specify this graph in "Graph" on the PCG component in the Details panel. Turn "Is Partitioned" OFF here for an unpartitioned setup.

The Volume is the range placed in the level and the graph is the placement rule used within it. They are not the same, so assign the graph to the Volume after creating it .
Connect three nodes
Open PCG_ForestPractice , right-click empty space, and add these three nodes.

| Node | Its role here | Connection |
|---|---|---|
| Get Landscape Data | Gets the Landscape's surface | Out → Surface Sampler's Surface |
| Surface Sampler | Creates candidate points on it | Out → Static Mesh Spawner's In |
| Static Mesh Spawner | Places a mesh on each point | Set the asset to place |
Select Surface Sampler and start from these values in the Details panel.
| Setting | Starting value | Meaning |
|---|---|---|
| Points Per Squared Meter | 0.1 | A guide for candidates per m². Raising it makes it denser |
| Point Extents | 50 on X/Y/Z | Half the size of the point's extent. We use the small default here |
| Looseness | 1 | Adds variation to point positions |
| Unbounded | OFF | Restricts to the Volume's range |
You do not need to connect the "Bounding Shape" input here. With Unbounded OFF and no other range passed in, it uses this PCG Volume's range.
Next select Static Mesh Spawner. Set "Mesh Selector Type" to PCGMeshSelectorWeighted and add one entry with the + on "Mesh Entries". Specify a tree or Cube in its "Descriptor → Static Mesh" and set "Weight" to 1 .
Save the graph, return to the level's PCG Volume, and press "Generate" on the PCG component. The specified mesh lining up on the ground inside the Volume is success. A Cube is placed with its center at the ground position, so seeing it half-buried still confirms candidates were generated. The Input and Output nodes present from the start can stay unconnected in this example.
When nothing appears, look at the "points" before the trees
When nothing appears, you do not have to hunt for the cause all at once. First confirm Surface Sampler is producing points.
Select Surface Sampler in the graph and turn Debug (displaying intermediate results) ON with the D key. Choose PCG_PracticeVolume 's component in the debug target field or "Debug Tree" and Generate. Small box markers appearing in the viewport are the candidates. Pressing D again clears the display.

- No points either : check the Volume-ground overlap, the graph assignment, the Get Landscape Data to
Surfaceconnection, and the candidate count. - Points but no objects : check the Surface Sampler to Spawner connection and the Static Mesh specification in Mesh Entries.
Once it places, change Points Per Squared Meter from 0.1 to 0.05 and Generate. Wider spacing means you can adjust the amount placed.
To try a different arrangement, change the PCG component's Seed . A Seed is the number determining the random placement pattern. Matching terrain, settings, and Seed in the same environment makes the same placement reproducible. Note the Seed once you get an arrangement you like.
Remove candidates on steep slopes
Next we exclude steep slopes where we do not want trees. We use that location's normal . A normal is "the direction extending perpendicular from the ground", straight up on flat ground and angled on a slope. Comparing that direction with straight up selects flat spots.

Add Normal To Density and Density Filter between Surface Sampler and Static Mesh Spawner.
Normal To Density writes how close the normal is to a specified direction into the point's Density . Density is a value points carry, used here to represent "how close to straight up". It differs from the earlier "how many points per m²" setting.

All connections go from the previous node's Out to the next node's In . Configure Normal To Density like this.
| Setting | Value |
|---|---|
| Normal | X=0 , Y=0 , Z=1 (straight up) |
| Offset | 0 |
| Strength | 1 |
| Density Mode | Set (replace with this value) |
Set Density Filter to Lower Bound=0.85 , Upper Bound=1 , Invert Filter=OFF . On versions showing "Keep Zero Density Points" and "Normalize Output Density", turn both OFF. Only points whose value is in the specified range continue.
Generate and see meshes thin out on steep slopes while remaining on flat ground. To restrict to flatter spots, adjust by raising Lower Bound . 0.85 is a starting point; decide while looking at your actual hill.
Stand trees upright and vary their size
Points inherit the ground's orientation too. To stand trees straight up, add Transform Points between Density Filter and the Spawner. That node changes points' rotation and scale. Rewire Density Filter's Out → Transform Points' In and Transform Points' Out → the Spawner's In .
| Setting | Value |
|---|---|
| Absolute Rotation | ON (replaces the rotation inherited from the ground) |
| Rotation Min | 0 on X/Y/Z |
| Rotation Max | X=0 , Y=0 , Z=360 (rotate only around the up axis) |
| Uniform Scale | ON (preserves proportions) |
| Scale Min / Max | 0.8 on each axis / 1.2 on each axis |
The order of checking the ground's slope before changing the trees' rotation matters. Placing Transform Points first and aligning the rotation also changes the orientation used to check the slope.
You now have trees of slightly varied size and rotation, centered on flat ground.
Clear the path area with a Spline
Let's run a tree-free band through the forest using a Spline , a curve you shape by connecting several points, serving here as the "path's center line".
Placing the line alone does not decide the path's width, though. Arranging points along the line and giving each an extent with width creates the band where trees are not placed.

What this article builds is space where trees do not grow. The ground's color and height do not change. To make it a dirt path, paint it afterwards with Landscape Paint.
Build the path's center line
- Create a "Blueprint Class → Actor" in the Content Browser and name it
BP_PCGRoad. - Open the Blueprint and add a Spline component with "Add". Turn "Closed Loop" OFF.
- In the Details for "Class Defaults", add one entry
PCG_Roadto the Actor's Tags . That is the marker for finding this Actor from PCG. Put it on the Actor, not the Spline's Component Tags. - Compile, save, and place one inside the level's PCG Volume. Leave the Actor's and Spline's Scale at
1, 1, 1. - In the level, select and move the Spline's points to make a line crossing the forest. Selecting a point and moving with
Altheld adds points so you can bend it.
We draw the path from above here and keep the Spline's points at the same Z height. Keep each point's Scale at 1, 1, 1 too. Putting the whole curve near the hill's base is enough. We build a tall exclusion volume next, so there is no need to trace the terrain's undulations closely.

Give the line width and height
Back in the PCG graph, build Get Spline Data → Spline Sampler → Bounds Modifier on a separate row from the tree flow. Each connection is Out → In .
Set Get Spline Data's "Actor Filter" to All World Actors , "Actor Selection" to By Tag , and "Actor Selection Tag" to PCG_Road . With one path here, leave "Select Multiple" OFF and "Must Overlap Self" OFF where present.
Set Spline Sampler's "Dimension" to On Spline , "Mode" to Distance , and "Distance Increment" to 100 . UE distances are normally cm, so that creates a point every meter along the line .
Bounds Modifier changes the extent points carry. Set "Mode" to Set and specify these values.
| Setting | Value |
|---|---|
| Bounds Min | X=-300 , Y=-300 , Z=-3000 |
| Bounds Max | X=300 , Y=300 , Z=3000 |
| Affect Steepness | ON |
| Steepness | 1 |
That is a box extending about 3 m to each side and 30 m up and down around each point. Steepness is how the value falls off near the boundary; we use 1 to separate inside from outside clearly. The one-meter-spaced boxes overlap into an exclusion range following the curve.

Because this method overlaps boxes, corners will not be a strictly constant-width band. Use it as a way to clear a roughly 6 m wide walkway . With large tree canopies, widen the X/Y extents for margin.
Pass candidates and the exclusion range into Difference
Finally add Difference , the node that "subtracts a specified range from the original candidates". Connect the two inputs distinctly so it is clear which is subtracted.

| Connected from | Difference's input |
|---|---|
Density Filter's Out in the tree flow | Source (the originals) |
Bounds Modifier's Out in the path flow | Differences (what to subtract) |
Set Difference's "Density Function" to Binary , "Mode" to Discrete , and "Keep Zero Density Points" OFF. Those settings remove candidates falling in the path's range and pass the rest along.
Disconnect the earlier Density Filter → Transform Points wire and rewire Difference's Out → Transform Points' In . Transform Points → Static Mesh Spawner stays as is.
The flow is now "make candidates from the ground → remove steep slopes → remove the path area → change rotation and scale → place".
Bend the path and rebuild placement
Save the graph and Generate on the PCG Volume. A gap following the Spline among the trees is success. Look from above first and confirm the curve and the cleared area match.

Next move the Spline's points sideways a little and Generate again. The gap changing with the path's shape means you can adjust the path without fixing trees one by one. Some settings auto-update, but confirm with Generate when you see no change.
Finally look from the player's height. Even without trunks, branches may overhang the path. In that case widen the exclusion range or reduce the tree size. A forest that looks tidy from above shows the margin it actually needs once you walk it.
| Problem | Where to check |
|---|---|
| Trees on steep slopes too | Normal To Density's settings and Density Filter's range. Transform Points, which aligns rotation, goes after them |
| The path area does not clear | Whether the Actor Tag is PCG_Road and Get Spline Data looks for that tag. Whether Spline Sampler's Debug shows points |
| It clears on flat ground but trees remain on tall hills | Whether the path boxes reach the ground. Adjust the Spline's height or Bounds Min/Max Z |
| Grass or trees remain on the cleared path | Whether they are hand-placed Actors or Foliage. Difference targets this graph's placement candidates |
| So much placement that editing is sluggish | Shrink the Volume or lower Surface Sampler's Points Per Squared Meter |
Bonus: good to know up front
Generate rebuilds the placement. Easy condition changes are PCG's advantage, but wide ranges and many candidates take time to process. Settling the rules on a small range before expanding keeps tuning manageable. We generate in the editor here and do not cover dynamic generation at runtime.
More trees means more rendering cost. Static Mesh Spawner batches the same mesh as instances, but overlapping foliage and shadows are not free. If it gets heavy after expanding, check with stat unit and also tune LOD and culling.
Confirm placement and collision separately. Even with trees visible, whether you pass through depends on the mesh's collision shape and the Spawner's settings. Decide whether they are background forest or trees that block the player, then walk it in game and confirm.
Building this flow once lets you swap trees for rocks or widen the roadside clearance, trying different scenery on the same terrain. Start by moving one path and finding how much margin makes a forest comfortable to walk.
Summary
- PCG follows "emit points → narrow them → place meshes"
- Remove steep slopes and the path at the point stage
- Change the underlying terrain or curve and placement can be rebuilt
The question to ask before using it is "is this important enough to place by hand?" Important things go by hand; things carried by sheer quantity go to PCG.
The cost of drawing many identical objects is in Instancing, and the terrain itself in the Landscape introduction.
Further Reading
- Landscape introduction — building the ground's shape and color and decorating roadsides with Foliage
- Instanced Static Mesh — the mechanism for drawing identical meshes together
- Epic: PCG overview — graphs, points, debugging, and placement basics
- Epic: PCG node reference — each node's role