Hi guys and welcome back, I’m Rob from State of Art Academy, here we are for another tutorial about Unreal Engine.
Today we’re going to build a custom scatterer via blueprints. I made this for a personal project to add details on top of other objects, and even with some limitations, you can use it to create a whole forest. Before starting, I want to spend a couple of words about #teamtrees, a project started from the famous YouTuber MrBeast this October. The goal is to plant 20 Million trees through your donations and the help of the Arbor Day Foundation. So, if you’re interested in helping the planet, please take a minute on https://teamtrees.org/ and plant a tree with a single dollar (or more!). I don’t know if we can plant 20 million trees with this scatterer, but let’s try anyway!
The idea is pretty simple. We want to create a box that defines an area. On top of the box, we define a grid, and from every vertex of it, we fire a line to the floor. If those lines hit an object polygon, something spawns at the impact point and it is aligned along the polygon’s normal.
1. Blueprint and components
Let’s create a new Actor Blueprint “Scatterer”. We need to work in the Construction Script tab; everything we do here happens directly in the engine viewport before the game starts.
I replace the default Scene Root with another Scene Root, and then I add a “Hierarchical Instanced Static Mesh” component. It’s a container for all the instances of a mesh I’ll provide. It’s very efficient because it’s only 1 draw call in the game, and differently from regular Instanced static meshes, we can add, remove, modify each element position, rotation, and scale. Ok, then create a new Box Collision component.
2. Box Setup
Let’s define the width, length, and height of this box with 3 new Float variables. Let’s drag a box reference in the graph and set the box extent with the so-called node. It measures values from its center, so we need to divide them in half. We could also move it up by half-height to place it on the ground. Remember to set your variables to “Public” if you want to change them from the editor.
3. Mesh Setup
To set up the mesh we want to scatter I create a public Static Mesh variable. Let’s define with it the static mesh inside the Hierarchical Instanced static mesh component.
4. Grid Setup
Now, with a “2D Grid Execution Macro” we can define rows and columns. I create a new float variable “Grid Size” to change the density of the grid (it’s basically the distance between each object). In “Center Location X” and “Y” we pass the X and Y value of the actor itself (this is the pivot of the grid). In the “Center Location Z”, we add the Box Height to push the grid to the top. For “X” and “Y” (the number of total columns and rows), we split the Box Width and Length by the Grid Size.
5. Tracing lines
Time to shoot some lines! I create the “Line Trace by Channel” node, which allows us to draw a new line for every grid polygon, but we have to specify where it should start and end. An excellent opportunity to practice with vectors. A vector is a position in the space or a direction. It’s represented by 3 coordinates; x, y, and z. The vector for the beginning of the line is at the center of every grid polygon. To define the ending point coordinates, I break the vector to update Z, subtracting the Box Height. As you can see, we can easily manipulate values with “Break” and “Make” nodes. I pick “For Duration” in the “Draw Debug Type” and set the “Draw time” to 0.1. If we move the bp around now, we’ll see all the lines, tracing the scene.
6. Analizing the hit
Every time a line hits something, we can track it with a “Break Hit Result” node. In this way, we get access to any information about the event. For example, we want to spawn a mesh only for those lines actually hitting something. From the “Blocking Hit” I get that condition, and we’ll go on only if it’s true.
7. Spawning meshes
It’s time to spawn meshes. To do that, we need to add instances to our Hierarchical Instanced Static Mesh component using the proper node. As you can see, I have to provide a transform input, which means a location, a rotation, and a scale. Location is the “Impact point” vector, minus this Actor location vector because our instances spawn inside the actor. The scale is arbitrary; we can use the same float variable in x, y, and z scale, for now. Rotation is a little bit more complicated because we have to align the mesh to the normal of the hit point. We can achieve that using a “Make Rot from ZX” and providing the “Impact normal” and the mesh normal with a “Get forward vector”. We can put together Location, Rotation and Scale into a “Make transform” and pass it to the “Add Instance” node.
After compiling, we can try the blueprint; it should work fine. What about adding a bit of randomness? The theory behind is simple: we let the engine to pick a random number in a range using a Seed. We decide the range with 2 floats and the seed with a “Random Stream” variable. The reason why we use the seed is to set a state that does not change every time you recalculate the blueprint. In this video you can see how to generate a random Location in X in a range with a seed number. The complicated part is to add/subtract random values at the right moments.
Location randomization in X and Y should be done before tracing lines (so object will continue to stick on the point hit); in Z should be done after (because the starting mesh Z-location is generated by the hit).
Rotation randomization and Scale randomization should be done before spawning the meshes (Rotation depends on the impact normal).
As you can see from the screenshots, I’ve created a few new public float variables to suit my needs about randomness. It’s also a good practice to group together similar variables and to comment the graph.
9. Final thoughts
Thank you for going trough this quick tutorial! Now it’s your turn to go on and modify it to fit your needs. For example, I successfully convert this mesh scatterer into a decal scatterer. If you have issues with the bp, you can download mine with the button below and copy it into your project. Have a nice day!