>> Hello, everyone, and welcome back
to Unreal Tips and Tricks.
Today, I want to show you how to use splines
and instanced static mesh components
to make useful and performant tools to quickly lay out
repetitive geometry.
We'll look at two ways you can use these two
components in a Blueprint to quickly place and edit
a lot of geometry in the world.
In both cases, we'll be making a Blueprint
that places copies of the mesh along the user-editable spline.
We'll expose a few parameters for our users,
determine the spacing between copies using the mesh itself,
then use that information to determine where to place
the copies along the spline.
Then, I'll show you how you can use that information
to make sure your copies follow the spline.
Let's dive in.
I'm here in our Advanced Vehicle template that
comes with the Unreal Engine, and let's say
I want to add some barriers around the racetrack.
I'll start with the stack of tires
I modeled using Unreal's built-in tools
and textured with materials from Quixel.
I want to add these to most of the corners
and turns on the tracks so that my car doesn't go flying off.
And there's a lot of twists and turns on this course.
Instead of dragging and duplicating them
all throughout the map, I'll show you
how we can use splines and instanced static mesh
components to really quickly place
a bunch of these tire stacks exactly where we want them.
In the Content browser, I'll right-click and say
Create Basic Asset Blueprint Class
and set the Parent Class to Blueprint to Actor.
I'll name that BP Spline Layout Tool and open it up.
In the Blueprint Editor window, I'll
click the Add Component button and type Spline.
I don't want to use a spline mesh
because I don't want my meshes to deform along the spline.
We want them to stay rigid.
This gives me a line, and I can click on its points
to drag it around.
I can Alt-click and drag to add points,
and I can change the tangents of it to customize the shape.
In many cases, you might have a function in your construction
script that adds static mesh components to the Blueprint.
However, this comes with some performance issues
both in rendering and in the construction script.
Since I know I'm using a single static mesh,
I can instead use an instanced static mesh component.
It basically says, take the static mesh I've specified
and stamp it around in a bunch of different places.
I'll hit Add Components again and type Instanced Static Mesh
and click it to add that component.
Since I'm making a tool for other users in my project,
I want to expose a few variables to them
so when they're placing this Blueprint in the world,
it'll be easy to modify.
The first variable I want to expose
is the static mesh we'll be placing along the spline.
I'll bring my instanced static mesh component
into the construction script, which will create a Get node,
and I'll drag off that and type Set Static Mesh
and select that function.
I'll connect the execution pin of that node
to the start of my construction script.
Then I can right-click on the new mesh pin on that node
and say Promote to Variable, which will automatically
create a new variable of the type static mesh.
I'll rename that to Placed Mesh and click the eye icon
next to it to set it to be instance editable,
so anyone placing this Blueprint can change this value
when the Blueprint is placed in the world.
I'll set the default of this variable
to my Stack of Tires asset.
We know we want to space these meshes a certain distance apart
from each other.
So instead of relying on a user-specified float variable,
we can use the mesh itself to get the spacing we need.
I'll create a Getter for my placed mesh variable
in the construction script.
And from that, I'll type Get Bounding Box
and from that, break structure, then
subtract the min value from the max value
to get the size of our mesh.
Next, from that vector, I'll create a Break Vector node,
and I'll use the size of the geo along the x-axis
since that's a common forward axis.
This will become more useful later.
This means we'll stack the tires right on top of each other
as we place them along the spline.
But I want my users to be able to control the spacing ever
so slightly.
So for that, I'll add an offset to this number.
In the My Blueprint panel, I'll click the plus icon
next to the variables category to make a new variable, which
I'll name Offset.
I'll promote this one to instance editable,
and I'll change its type to float.
From the X output of the break vector,
I'll create a float + float node
and connect our offset variable to it.
This lets me offset it forward or backward along the spline.
So if I want to be able to offset further,
I can just type positive values.
Or, if I want them closer, I can use negative values.
I'll recompile my Blueprint and set that default
offset to five or so.
I'll right-click on that offset plus x-size output pin
and select Promote to Variable.
And I'll call this variable Spacing.
I don't want to make this instance editable, though,
since we're automatically calculating it.
Next, we need to figure out the number of instances we're going
to place along this spline.
First, I'll bring the spline from the Components panel
into my graph, and from that, say Get Spline Length.
From there, I'll create a float divided by float node
and divide the length of the spline by our spacing value.
This will give me a float number with some sort of remainder
or decimal because we're not always
going to have a spline with the perfect size.
I'll need to convert this to a whole number.
And to do this, I can either ceil it or floor it.
If I ceil it, it'll round up to the nearest whole number,
or if I floor it, it will round it down to the nearest integer.
Because I don't want to place meshes
past the end of the spline, I want to round down.
I can drag off the division and type Floor,
and I'll right-click on the output of the floor node
and select Promote to Local Variable,
and I'll name this Number of Instances
and connect that to my earlier nodes.
From here, I'll make a For Loop and use my Number of Instances
variable for the last index.
I'll take the index output of the For Loop
and multiply that by spacing.
This will be how far along the spline
we should place our mesh or the total length of meshes
we've placed along this line so far.
I can once again drag off my spline component
and type Get Location at Distance
Along Spline, which will give me a local space
location for a point that is a given distance
from the start of the spline.
From the Get Location at Distance Along Spline output,
I'll create a Make Transform node.
We'll leave the rotation and scale set to their defaults
for now.
So this is now a transform in local space
for the current instance.
Next, I'll bring the instanced static mesh component
into the graph, from it create an Add Instance node.
This tells the component to stamp this mesh
at this transform.
I'll connect my Make Transform node
to the transform input of the Add Instance node,
and we'll see what happened in the Blueprint viewport.
Hey, that looks great.
When I place my Blueprint in the world,
I can click on the spline and drag it around
to get my row of tire stacks to fit around
the curve of this track.
This technique works great when you have a mesh with a roughly
square footprint that you want to place at regular intervals.
There's so much you can do with this,
and I encourage you to explore the possibilities.
I'll show you one more thing you can do with your spline layout
tool, though.
If I swap my stack of tires for this concrete barrier
that I got from Quixel Megascans,
you'll see that our instances don't follow the curve
of the spline anymore.
That was less of an issue for our stack of tires
but becomes really apparent with a more directional mesh
like this.
We need to get these concrete barriers pointing
toward each other.
To do this, I'm going to get the location of the next instance
and use that information to create a rotation
value that we can pass into our Make Transform node.
I don't want to simply copy and paste this bit of functionality
here because I'm the kind of person who doesn't like
to do the same thing twice.
Instead, let's wrap this up in a function.
In the My Blueprints panel, I'll click the plus icon
next to the functions to create a new function
and name it Get Location at Index.
I'll select all these nodes for my
For Loop to my Get Location at Distance
Along Splice node, right-click and select cut.
Then, I open that Get Location at Index function,
press Control-V to paste.
Now, you can see that the integer
input into our multiply function is empty.
We can click and drag on that over to the function node
to create a new input variable.
Similarly, I can drag the location output
of my Get Location at Distance Along Splice node
onto that same Function Start node
to create a vector return value.
I'll connect my Get Location at Distance Along Spline
output to that return value and make
sure that the start of my function
is connected to the return node here.
Now, if I go back into the construction script,
I can place my Get Location at Index Function into the graph
and connect that into my loop body.
I can connect my index to the A input and the return value
to my make transform node.
However, I'm going to need a second one of these,
and I'm starting to feel a little cramped in the graph,
like my Blueprint is getting clogged up.
Since our Get Location at Index function
doesn't change anything about the Blueprint
or call any other functions, we can make this
a pure function, which means it won't have any execution pins.
I'll select the function in the My Blueprint panel
and select the Pure checkbox.
You can see it change to a green icon,
and in the construction script, you
can see that it doesn't have any execution pins anymore.
I can right-click on that node and select Duplicate.
And for the input of this function,
I'll add one to the index from our For Loop.
I'm going to pause here since you
may think we're about to run into trouble if we pass
in an index that is greater than the number of meshes
that we want to place and, thus, finding
a distance along the spline that is
beyond the actual length of the spline.
The good news for our purposes is
that the Get Location at Distance Along Spline function
will return the endpoint of the spline
if the distance is longer than the spline itself.
So for the last point we need to calculate our rotation,
we'll always get the end of our spline.
So now I have my location of the current instance
and the location, of the next instance
or the end of my spline.
We'll need to make a vector that points
from the current location to the next location and use that
to make a rotation.
And to do that, all we have to do
is subtract the location of the current instance
from the location of the next instance.
From there, we'll create a Make Rot from X node.
This takes that vector as an input
and makes a rotation value with that vector as the quote
unquote "forward vector."
We can connect the rotation output of that node
to the rotation input of our Make Transform node.
In the Blueprint viewport, we can see nothing has changed,
which, again, is what we want to see.
In the Level Editor, though, we can see now
that the concrete barriers are properly aligned and pointing
toward each other.
And you can see as I move the spline around
and add points to it, we're making more barriers,
and they're all connecting up.
And that's it.
Now we've got this really useful and reusable instanced layout
utility that can work in all sorts of directions,
elevations, distances, and angles.
If I ever want to change this racetrack,
it won't take me that long to put down new splines
to adapt to its shape.
There's so much you can do with these concepts.
You could use this to make fences,
place street lamps along a road, or trees along a trail.
You could even use this to make chains.
You could add functionality to jitter the offset,
or push the instances side to side.
You could randomize the rotations of meshes
within a certain range, add controls
to select which axis to use for the sides of the mesh.
This is just the beginning.
I hope you have fun exploring all of the possibilities
with this tool.
Thanks for watching.