Created using blueprints (no coding needed)
Blueprint Event Dispatchers
Blueprint Custom Events
Before jumping into explanation how to create a forest generator using blueprints we need to figure out how to randomly generate forest. First thing that comes to mind is just randomly pick location from spawn area and place tree there. But this solution creates lot of problems. All trees can spawn in one spot or create clumps, that means won’t be evenly distributed across area we want to populate. Trees can also spawn on another trees and we definitely want to avoid that behavior in our generator. To achieve this we can give a tree that we want to spawn it’s own area. To create that we divided our foliage area into a grid. In one grid cell we can only spawn one tree. By doing this, our forest from being created fully random now is fixed and dull and definitely does not look like a natural one. But on the other hand there is no longer a problem with colliding models. To put more life into the woods and to make them more natural we can use a simple trick: when tree is created it’s location is randomly chosen. But instead choosing the location from whole spawn area we use the range of a grid cell the tree was spawned. After we know the general idea how to create the forest lets jump to blueprints.
General plan how the job should be done:
Place Start Worker Blueprint into scene ⇒ Activate it ⇒ Start Worker generates grid and spawns first Worker ⇒ Start Forest activates Worker ⇒ Worker creates fixed number of trees ⇒ Worker notifies Start Worker that the job is done but forest is not finished yet ⇒ Start Worker creates another worker and activates it ⇒ repeat until Worker notify Start Worker that whole forest is created
By doing it this way whole forest won’t be created during one application tick, so if area to populate is large it won’t freeze the game.
Custom structure was used to represent grid cell. It consists of three vectors representing top left corner, center, and bottom right corner of grid cell and a boolean value that will be helpful during spawning.
Start Worker Blueprint:
Variables to control the forest generation:
- Number of Trees: the amount of trees to spawn
- Tree Density: number from 0 to 1 controlling tree density (default 1 means blueprint will attempt to spawn amount of trees equal to Number of Trees variable)
- Radius: radius of foliage area that will be populated with trees
- Grid Cell Size: size of grid cell
- Tree Scale Min: minimum scale that can be applied to spawned tree
- Collision Range Trace: Range of collision trace
- Max Slope angle: max angle of slope that tree will spawn on
- Max Object for Worker: amount of trees that one worker can create during its lifetime
- Trees to Spawn: Static Mesh array holding model of trees to spawn.
- Tree Radius: array holding radius of trunk for tree that index from Trees to Spawn is corresponding to index from this array (sadly there is no map container in blueprints thats why we need two separate arrays to hold trees and radius of trunks)
The heart of the system. This is where all the calls are dispatched and workers are created.
Custom Event: Generate Grid:
This function is a starting function for foliage creator. For speed and overall performance this blueprint is using Static Mesh Instances, but the worker can spawn anything (actor, blueprint etc.). It creates as many Instanced Static Mesh Components as there are elements in Tree to Spawn array and the sets Static Mesh for them. When the component is created then it’s added to Instanced Trees array.
After this process next function is called:
The purpose of this function is to determine the max amount of trees that can be created based on Radius and Grid Cell size array. It calculates how many rows / columns the grids will have and what is the amount of trees that the grid can hold. After that Number of Trees passed by user is its clamped between 0 and max and then multiplied by Tree Density.
It creates two arrays in loop fired up in another loop. It allows for easy grid creation. To calculate X coordinate it takes index from the first loop and multiplies it by a Grid Cell size Variable and then subtract a sum between Start Worker X coordinate and spawn area radius. Same with Y but index is taken from second loop. Z coordinate is not important in this process so we can skip it. This produces Top Left corner for Grid Cell. To get other two vectors X and Y coordinates subtract half of the Grid Cell Size. After the grid cell is prepared it is added to the Grid array. During this process Rand Grid array is also filled with values of indexes that Grid Cell were added. It will be needed later.
This function calculates in which grid cell tress will be randomly planted. In a loop of range from 0 to Number of Trees an item from Rand Grid is randomly picked. Based on its value (representing index of a grid cell in Grid array) it changes the boolean value in Grid Cell to true. To avoid drawing this grid cell again, item from Rand Grid representing this grid cell is removed.
Spawn Worker Custom Event:
This Event has an input node, that means when it’s called it will pass this value.
Passed value represents last index in a Grid array that was used to create a tree, so next worker knows where to start. When the event is called it spawns actor from passed class. Worker needs info about the work so additional variables are passed during it’s creation (how to achieve this will be explained later in worker section). After the spawn is completed events are binded to dispatchers in worker (also explained in worker section).
After creation is completed the call chain ends. To start a Worker, in every tick (Event Tick) the Start Forest gets all Actors that implements BPI_WorkerDispacher interface and calls Start Worker function. It will tell the Worker to start spawning trees.
This will help to keep communication between Start Forest and Worker simple. Start Forest can simply take all blueprints that implements BPI_WorkerDispacher and call needed function on them.
More info: Blueprint interfaces
If event is binded to Event Dispatcher it will be executed when the Event Dispatcher is called. This allows for smooth communication and code execution between multiple blueprints. When Worker is created by Start Forest some of it’s custom events are binded to Event dispatchers in Worker blueprint. That means when the Worker will call an Event Dispatcher a event binded to this dispatcher will execute in Start Forest blueprint.
More info: Event Dispatchers
Expose Variables on spawn:
In variable details: editable and expose on spawn must be selected. This operation allows variables to be initiated when actor is spawned. It is used to tell the Worker where to start in Grid array, what trees can be spawned etc.
Simple function tracing against Landscape. Range of trace is calculated from the randomized spawn position and Collision Range Trace variable defined by user.
Check Slope Angle:
This Function does two things: calculates slope angle and check if tree can spawned (checks angles between a slope and angle defined by user)
Function responsible for adding instances of trees to the map. It draws random tree and takes its radius. Based on this radius, function calculates safe distance that is used to find random location for spawn inside a grid cell.
After getting location to spawn Trace is called to get the Z coordinate. If Trace hits landscape, the slope is checked. Next, based on tree radius, slope angle, and Z coordinate of Start Forest actor (the owner of Instanced Static Mesh Component) Add Trees calculates how deep tree needs to be located on the landscape so it doesn’t partially float in the air. The rotation and scale is set randomly to add more life to created forest.
When Start Worker is called the main loop in Worker (starting from the last Grid Cell used by previous Worker) it spawns trees using Add Trees and increases objects created counter. When the loop ends or if Worker creates its defined number of objects, Event Dispatchers are fired up, calling binded events from Start Worker like Spawn Worker or notification that whole forest was created and job is done.
- Place downloaded blueprints and structure in Game/Blueprints/ folder (/[Your_Game_Project]../Content/Blueprints)
- Add Start Worker to your map
- location where you put this actor is a center of foliage area that will be populated with trees
- trees will only spawn on landscape
- setting radius of foliage area too big and Grid Cell size too small may result in Runaway loop
- setting Max Objects for Worker too high might freeze application
- fill up Trees to Spawn array
- fill up Tree Radius array so first radius corresponds to first tree in Trees to Spawn array
With this base you can develop more complicated system. I manage to add 3 more “layers” to the forest, first one was trees, second bushes, third small props (small rocks etc.) and the last one was decals. Every layer creation worked almost the same like trees layer with some changes. For example props were rotated to match orientation of surface, and all objects had more randomization added to their transformation matrix.