[MUSIC PLAYING] Hello, everyone. My name is Daryl Obert, and I'm
a Technical Marketer at Epic. I've been using the
engine for quite a while. Prior to that, I was mainly on
the film and TV side at Maya, worked at Autodesk
for a very long time. So I think I see some
familiar faces out there, good to see y'all. Thanks for coming. Today's class is an
introductory to PCG, so it's going to be covering
basic core concepts. We're not going to be going
down too deep into it. There are several
other PCG classes that are being given at
Unreal Fest this year. So if you want to get into
something a bit deeper, I definitely recommend
after this one, maybe trying to see if you
can get on your schedule some of the other classes
that are a bit more in depth. But what we will be doing
is hopefully giving you guys an understanding
of how this works, kind of coming from the
persona of a DCC artist. So coming out of
Houdini or maybe Gen and Maya, or
Bifrost, even RailClone. And Max, even some of the
geometry nodes and in Blender, have very similar
ideas behind them. At the end of the day, this is
a procedural content generation tool. What we're really doing is
we're just [INAUDIBLE] stuff. That's at the core
of what we're doing, is we're essentially
sampling data. We're taking points
and space, we're filtering those and
playing around with them, and then we're going to
spawn things from them. So that's the approach of what
I'm going to be showing here, is building up some
basic tools that give you that same
functionality that you might be used to coming from
a traditional DCC background. So we're going to
start off today by building some
roof tiles on this. And then we're going to
get a bit more complicated and start building
out that fence. So let's go ahead and
jump over into Unreal. And we'll start going through
some basic concepts on how you can spawn some geometry
based off of other meshes and things like that. That's really what we
want to get through in this very first section. All right, so the
first thing that you're going to want to do,
if you're working with PCG in your
own projects, is make sure the plugins
are turned on. So go to settings,
plug-ins, search for PCG. And you can see in
my project, I already have procedural content
generation framework turned on, as well as the PCG
geometry script interop. And geometry script and
PCG can work together to do some crazy
powerful things. In my presentation, a couple
of the nodes that I'll be using utilize this geometry
script interop to work. They actually
wouldn't even show up if this plugin wasn't turned on. So I'll make sure
to identify those when I'm working with
them, just so you're aware which ones they are. All right, so with that
said, what we want to do is, we want to create a new
roof on this tree house, that's going to be a tile roof
based on a Quixel asset that I've already downloaded
with Quixel Bridge. It's worth noting that
all of the geometry that makes up this tree
house are Quixel assets. They're just Quixel assets
that I downloaded, and then Kitbashed together using
some of the modeling tools inside of Unreal. It's also worth noting
that the background environment is based off of the
Electric Dreams Sample Project. And Electric Dreams
is an amazing project, if you want to learn
more about some of the more advanced topics
in the procedural content generation framework workflow. It's a really, really deep, deep
project that you can dive into, that goes well beyond what we're
going to be covering today. So to get started,
let's go ahead and turn off that wooden roof. And I'm going to turn on
these four static meshes, that are going to assist us in
the creation of our PCG graph that's going to
make our tile roof. What we want to do is,
we want to sample points on this geometry,
this roof geometry that we just turned on. And then instance to
those sampled points, the roofing tile from
that Quixel asset that we downloaded already. So to make it a bit easier
to work with in the PCG graph, what I'm
going to do is, I'm going to actually merge
these four pieces of geometry together into a single static
mesh using the modeling tool. So if we click on
modeling, and go to Xform. Click on merge, and then
click the accept button. You can see in the
outliner, we now have a combined static
mesh that makes up all of those roofing pieces. Now, the next thing
that I want to do while I have these
modeling tools up, is I actually want to add a
deformation onto this roof, to give this ridgeline a
little bit of sway or bow. So that it looks
more similar to what we had with that wooden roof. So we'll click on deform,
and we'll just add a lattice onto that piece of geometry. Go in here and grab this
control point on that lattice, and drop it down. Now, you can see that it's
using a linear interpolation between these two points
that doesn't look that great. So we'll switch
that over to cubic, and it'll average that
across all the polygons that make up this
roof, to have its kind of nice, smooth
swaying roof line across that ridge of the roof. So we now have a single
piece of geometry that is ready to go, and
use in our PCG graph. So let's go ahead and start
creating that PCG graph now, by jumping into
the content browser and going down into a folder
that I've already created. And what we want to do
to create the graph, is just right click in
the content browser. Go to PCG, PCG
graph and give this a name that's a little
bit more meaningful. So we'll call it
PCG_roof, oh, I'm spelling things completely wrong today. Roof, and Unreal Fest. All right, cool. So we've got this graph. It lives in our project, but it
hasn't been added to our level. So for it to show up in the
level, we need to add to it So we'll just drag and
drop that into the level. You can see it's
now in the outliner. And then the next
thing we can do is go back into the
content browser, and double click on that
graph to open up its editor and begin creating
some nodes, that are going to ultimately create
a tiled roof on our little tree house. So this is the PCG graph window. I'll give you a quick
overview of it now. So the middle graph
window is pretty similar to the blueprint graph or
even the material editor, similar to both of those. Details panel is just
like all the details panels that live
inside of Unreal. I'm sure you've used that a ton. On the left hand side
are all the nodes that you can use to
create your graph logic, so sampling nodes,
filtering nodes, math nodes, all kinds of nodes
that you can use to create crazy cool graphs. If you right click inside
of the actual graph window, you get a pop-up that
also has all of the nodes that you can use to
create the logic. So you don't really have to
have this left hand panel turned on if you don't
want it, because you can get the information right
here by right clicking directly in the graph window. Then on the bottom,
is the window for inspecting the metadata
that flows throughout the graph. So as you click on
different nodes, you can basically enable
and disable the ability to see the different data
that exists in your graph. And that data is very useful. We'll use this window
a bit more in depth as we start to build up
some more complex graphs. So more of that to come
throughout the presentation. So with that said, let's go
ahead and start building up a graph that's going
to give us roofing tiles on our little tree house. So the first thing
that we want to do, is we want to go ahead and
sample this piece of geometry to create some points. So to do that, we're
going to right click and we're going to
do a mesh sampler. So the mesh sampler is
one of the nodes that actually uses geometry scripts. So if you didn't have the
PCG geometry script interop plugin turned on, that
node wouldn't show up and that's why. So if for some reason you
right click and it's not there, turn the plugin on
and you'll be all set. And you actually use
the mesh sampler a lot, so just make sure that
plugin is turned on. So we drop that
guy down, and you can see that it has an error. The reason it has an error
is because we haven't added a static mesh yet. So let's go ahead and
add in that static mesh that we just made, which is
the combined static mesh. And as soon as we do
that, you can see here it is and everything's happy. The sampler is no
longer complaining. So now we've got this
sampler trying to sample one point per triangle, great. What do we want to do with that? Well, we want to take
that sampled information, and we want to
spawn a static mesh. So if we drag off of out pan and
search for static mesh spawner, you can see we've now got
these two nodes wired together. Let's just highlight those
guys, and hit Q to line them up. And what static mesh
do we want to spawn? Well, we want to
spawn a tile mesh. And there's a few different
ways the static mesh spawner can work. We're going to leave it on the
default, which is weighted, static mesh selected weighted. What weighted means is, you
can add multiple mesh entries. And you can adjust and bias
how much any static mesh is going to be represented,
based on the weighting that you've assigned. Now for this, we're only
using one roofing tile, so we're just going to click
the mesh button one time and add one array element. So in that array element, we're
going to go and add in the mesh that we want instance on
that sampled data, which is going to be a tile
that I got from Quixel. So it's just a
simple roofing tile. So cool, we've
now got a sampler. We're spawning static
meshes off of that data that we've sampled, and you look
in your viewport and nothing happened. And actually something
happened, but you don't see it. The reason you don't see
this, is because it's over here to the side. And you might be
thinking, well, heck, why is it over
there to the side? The reason it's over there,
is because this is actually where the origin is. If you look at the piece of
geometry that we're sampling, it's always going to be
using the static mesh. So this piece of geometry,
it's got an offset in it. Like we've pushed that
guy way, way over. My tree house is
not at the origin. So what does that mean? Well, it means if we
go back to this mesh and we drop it in our level,
and we zero out its transform, you can see that's that
mesh at the origin. And then you can
see, hey, guess what? This spawner-- this sampler
happens at the origin, and then the stuff
that's being spawned is happening at the origin. So it's not where we
want it in world space, and that's OK for now. Let's just get the
roof looking cool, and then we'll sort out
offsetting it and aligning it with the actual piece of
geometry a little bit later. So how do you change
the way this roof looks? Because right now
it's not looking good. I have these tiles,
but they're too small. They're going the
wrong direction, they're actually
tiled in a weird way. So the first thing
I'm going to do is, I'm going to go
back to my mesh sampler. And instead of having it
sample once per triangle, I'm going to switch it to
sample one point per vertex. So that's putting out points
for every vertice now. Great, looks great. The problem is, it's
going the wrong direction and they're too small. So what we want
to do, is we want to modify these
points that we've generated with the
sampler before they get to the static mesh spawner. So how are we going to do that? Well, we're going to modify
them with a transform point. So if you search for TR-- and this is a great tip for
searching anywhere in Unreal, you don't have to
write out transform. I'm really bad at spelling,
that would be hard for me. So if I do TR space PO, it
gives me the first word and then the space, and then
the second word. So just two letters,
space two letters and you could do that a
third time, a fourth time, it doesn't matter. So now we got the
transform points, great. Let's go ahead and
break this connection. And why are those guys up? Looking good. Now, we have a transform
points in here, but we actually haven't
transformed it in any way. So the first thing
that I'm going to do is, I'm going to spin
these guys around. I'm going to go in
the correct direction. So we're going to do
minus 90 and minus 90. And you know what? I actually want to have a
little bit of variation on this. So we'll do like minus 88
and then like minus 93, so that they have a little
bit of wobble on them. There's just like 5 degrees
about, of just randomness, rotating those guys around. And then the next
thing we're going to do is, we're going
to make them big. We'll make them like 5 by 5. So OK, cool. They're starting to look a
little bit more like a roof. Now, they're a little bit long
for this kind of stylized roof that we're doing here. So what I'm going to do, is
I'm going to turn off the lock. And come down here and
turn off uniform scale, and we'll make this
like 2.7 by like 33. So again, there's a little bit
of randomness, some of them are a little bit
longer than others. We could even do 2.6
or something like that. So that starts to look
a little bit better. Now, the next thing
that I want to do is, I want to translate
these guys down a little bit. So I'm going to do
minus 28 on that. Oops, that's rotate, that's
not what I want to do. Let's zero that guy out. So a lot of
experimenting when you're playing around with this. We want to go to offset. So we want to do minus I
don't know, 25 on that guy. And then maybe a little
bit more like minus 28, just to offset those so
that they're starting to look a little bit better. And then also, if you
look at this right here, you can see that
they're not very high. That roof that
they're spawned off of is kind of coming
through, so I want to pull them out off the top
of that roof a little bit. And you can see it here
on the backside too. So if we do something
like 10 on that guy and maybe like 18
on this guy, we're going to pull them out so that
they're sitting up a little bit higher. And that starts to
look pretty good. It might be a little bit
too far maybe or maybe something like 15 on that. And then I can give it
all a little bit more of random rotation. So we'll just do like minus
2, to I don't know, to 4, 5, minus 3 to 5. So they're just kind
of randomly broken up with a little bit of
change in rotation, a little bit of
change in length, a little bit of
change in transform. And it gives us a
really nice tile roof that's got this sort of
fun little look to it. And maybe some of these guys-- let's see, what
if we do something like 12 and like 4 on that? That looks a little bit better. Yeah, so that's kind of fun. So like I said before,
this is at the origin. My tree house is over here. I want that roof to align
with this piece of geometry. So how do you do that? Well, there is a node in
here called Copy Points. And Copy Points is a
workhorse inside of PCG, you're going to use it a lot. So what we want to do is,
we want to copy the points and combine them together
of these two meshes. So if we take our
transform points, which has got them looking
good, and we drag out and we do a Copy Points, that's
going to give us our source. Now, the target that
we want is going to be this piece of geometry. So to get the position of
that piece of geometry, we're going to use another
node called Get Actor Data. So Get Actor Data is
interesting like there's lots of different things you
can do with get actor data. So what we're going
to do is, instead of having it filter
itself, we're going to tell it to look
at all the world actors. So then it's going
to want to tag. And the tag that we're
going to look for is DTO. Got to spell correctly,
so let's put DTO in there. Let's take this piece of
geometry, let's search for tag down here. And on our actor tag, I'm
going to add a new one and we're going to call it DTO. So that's cool. We can take that, and
throw that in there. And let's just
break that, do that. Let's align this stuff
up so that it looks nice. Look kind of nice, not
perfect, but it's OK. Now, I did that, what happened? You don't see anything. It's actually sitting up here. And wow, that's a
lot of roof tiles. The reason that
it's so many roof tiles, is what this Get Actor
is sampling is not what we want. We don't want the mode to
be Parse Actor Components. We want it to be the single
point, its transform. So as soon as we switch that to
single point, just like that, our roof is now exactly
where we want it. So let's go ahead and
just close that down, and check out our cool little
roof that we just made. So that is the basics, that's
about as simple as it gets. We're doing something fun. We're doing something
very architectural with the procedural
content tool, which I think is super fun. So the next thing
that we're going to do is, we're going to
go ahead and we're going to create a spline-based
tool that allows us to scatter things down a spline. We're going to build a
fence, and then we're going to build a
more complex fence. So let's go ahead and
jump back into Unreal, and create that simple
spline-based tool. So step one is to
create a blueprint, and this blueprint is going
to be an actor blueprint. We'll give it a
name, BP_fenceuf. And if we double
click on that, there's a few things we want to set up. So we don't want to have
start on tick-enabled, and we need to add two
components to this. The first component is
going to be the spline. This is going to let us
generate a curve that's going to define where our fence
exists, and the shape of it. Pretty straightforward,
and you can see that curve just showed
up in the viewport there. The next component
that we want to add is actually a PCG component. So we'll search for PCG, and
we'll add that PCG component into the blueprint. And if we highlight
the PCG component and go down to
the details panel, you can see that it's
expecting a PCG graph. We haven't made a graph
for this fence yet, so let's go ahead
and do that now. We'll hit the content browser
one more time, right click and create a new PCG graph. That's going to be the
PCG graph for our fence, so we'll call it fenceUF. And with that still highlighted
in the content browser, I'm just going to jump
back into the blueprint and click the little arrow
here to make that connection. So it's now mapped into
that instance slot, pretty straightforward. So with that done, we
can compile the blueprint and save it. We're all done with
the blueprint now. So let's go ahead and just
pull up that content browser one more time, and let's
drag that blueprint out into our level. So there it is in our level. And you can see there's that
little spline-based curve that's on it there. I want to add in a few more
control points on that. So if I just highlight that
curve and hold down my alt key, I can just start dragging
out a few more points. And we're just going to get
a fence that shoots down the length of my tree
house here or maybe give it a little bit
of movement on that, just something like that,
so it looks a little bit wavy as it shoots down
in front of our house. So the next thing
that we want to do, is we want to start
adding in information into that procedural
content graph, on how to work with this
curve and generate some meshes or spawn some static meshes. So let's go ahead and
load up that PCG graph by highlighting it, and
double clicking on it to get the editor up. And step one is getting
information about this curve into the PCG graph, and
that's really easy to do. If we right click on this
and search for spline, we're going to get all
the nodes that allow us to work with spline data. So what we want to use
is the get spline data. Step one is getting that
spline data into the graph. You'll notice that
it's set to self. That's actually totally fine
that it's referencing itself in this example, because
in our blueprint, we've got the spline,
we've got the PCG graph. It's all contained
within that blueprint, so referencing
itself is actually what we want to do in
this particular example. So now that we've got that
spline data in the graph, the next thing we
want to do, is we want to begin working with it. And let's go ahead and search
out for those spline tools one more time. What we want to do is we want
to sample that spline data, and we want to use that
sample data to create points that we're then going
to spawn geometry from. So instead of using a
mode of subdivision, which is the spacing
down the curves here, we're going to set this to
a fixed distance, a fixed increment distance. And now that that's
done, we can go ahead and we can spawn a mesh. So if we do a static mesh
spawner, very similar to what we did for the roof,
we're going to want to define what type of
spawning happens here. So we're going to
leave it unweighted like we did for the
roof, and I'm just going to come down to mesh
entries and just click the plus sign to add an entry. Go down to index zero, and
we want to map something into this static mesh slot. Now, what we're going to map,
is actually some geometry that I downloaded from Quixel. So this is just a single chunk. This is actually how
the fence came, where it's a post with two rails. And that's going
to be what we're going to spawn our
instance down that curve. So if we go back to
our graph and bring up the content editor,
you can see it's still highlighted in there. So all I have to do is click
this little arrow button, to map that into that
static mesh slot. And there you go,
you have a fence, but its spacing is a little off. So we're going to go
back to the sampler. And in this sampler, we're
going to crank that up to a value of something like 250
so that it looks a little bit better. And I need to offset
this here, middle point is where the pivot
on that chunk is. So that's why it's
starting where it is. So that looks OK. Now, the thing that's
kind of cool about this, is like, if I wanted to change
the length or the shape, or anything with this, it's
now just a procedural tool. Like I could move that point in. I could hold down my alt
key and add another point, and we can use this stuff to
start to get these fences to do exactly what you want. I just want to have it round
that corner nicely, and wrap around my little
tree house there. So just like that,
we've now built a nice spline
distribution tool using a blueprint and a
little bit of magic in the procedural graph
network, pretty straightforward. So the next thing that we want
to do, is we want to go ahead and-- actually I
want to change this. I want to move this point out. I want it to be out here, a
little bit more like that, looks better. The next thing that we're
going to want to do, is we're going to want
to go ahead and add on that moss, that
moss that lives on the top of this
piece of geometry. So that's very similar to
what we did with the roof. We want to sample this static
mesh, this chunk of fence and use that to create points
that we can then spawn geometry from. So we're going to
do the same thing we did for the roof, where
we did a mesh sampler. And with that mesh
sampler highlighted, if we look in our
content browser, this modular chunk
is still highlighted. So all we have to do is
click that little map button, that little arrow
button to add that in. So that's going to be our chunk
that we're going to sample. Now, we're going to
use that Copy Points. Copy Points, you
use all the time. We did this for the roof. So we're going to say
Copy Points, so this is going to be our source. So we're going to get all the
vertices, like this is set to be one point per triangle. And what we want
to do is, we want to have that happen for each
individual chunk of fence that the spawner has spit
down the length of that curve. So we're just going to
take the output of that, and shove it into the
input of the target. So we've got something
happening here. You don't know it yet,
because we're not displaying any of the debugging data. But as soon as we
turn that on, you're going to see that we're going
to have points going all the way across these fence chunks. So to turn debug on, you
can right click on the node and just hit the
debug box or you can use the hotkey
D. So as soon as we do that, you can see OK, cool. There are all of my points that
are being spit out, awesome. And if I make changes
to this mesh sampler-- like instead of one per
triangle, we do per vertex, --you can see that that
distribution changes, very, very straightforward. Now, I did mention the fact
that there is the ability to view metadata that's
happening throughout the graph down here in this bottom panel. And the way to do that--
just to give you guys a quick overview
of that, --is turn on the blueprint
that we're using or the graph that we
want to visualize. And then on any of these
nodes, if, you right click on top of it
you can say, inspect or you could hit the a key. So if we inspect
this node, you can see that it's got seven points
and the seven points all have positional data. So those are going to be my
seven chunks shooting down the length of that curve. Now, if we were to
inspect the spawner here, notice that the data
changes a little bit. So the points are in
the exact same spot, but the min and max
bounds all changed. And we now have this
new string added. So this notion of
seeing the metadata and inspecting the
metadata, really lets you understand
what's going on. It gives you this nice view. So if we inspect the
data on the mesh sampler, you'll notice that we're
getting 2, 792 points. And they all have a density
value of 1, by default, everything starts with
a density value of 1. So that's how many that's
how many triangles I have on each one of those chunks. So if I was to
inspect this node, it's going to be a lot
higher because it's going to be basically
the combination of all the points going down
that length of that curve. So we briefly talked
about density. And density is one
of the workhorses that you're going to
use a lot when you're doing procedural content work. Basically, what density
allows you to do, is set grayscale values
on all the points that exist in your network. And you can then filter that
data to turn off or prune points out of the mix, so
that they're not contributing to the spawner for instance. So that's exactly
what we want to do. We want to basically
take these points, and we want to get a
grayscale value that represents the top of
the pieces of geometry. We want to run some filtering
operations on these guys, to isolate the points that only
exist on the top of our fence. So how do you do that? It's actually really
pretty straightforward. Let's go ahead and
turn off the inspector. What we're going to do, is we're
going to pull off of this guy and we're going to do
a normal to density. So when we do the
normal to density, if we disable the debugger
here and turn it on here, you can now see that we're
getting grayscale values. So the kind of gray
is a value of 1, and then Black is a value of 0. So this is now driving
that density value based on this vector,
that normal vector that's been defined here. So what we want to do, is
we want to actually use this to essentially
get rid of the points on the bottom part of the fence. So how do you do
that? well that's just done with a simple filter. So if we search for filter-- I've got to spell
it correctly, --you can see there is
a density filter. So we run that density filter. And again, let's just debug
that by isolating just this one node here. You can see that we're
now only getting points on the very top of
our fence chunks, as they shoot down that curve. And you can adjust this to
get more or less points, based on the values where it's
going to clip essentially, so pretty straightforward. Now in this example,
I really want to have that moss
be very, very dense. So having one point per triangle
or one point per vertice is not enough points. So what we're going
to do, is we're going to go back to
this mesh sampler. And in this mesh sampler, we're
going to turn on voxelized. So this is using those
geometry script nodes, that kind of voxelizer
lives in the modeling tools. So if we turn on the voxelizer,
at a voxel size of 100, all of our points have
gone away, makes sense. If we put this down to something
like, I don't know, 10, some points are
going to come back, but they're still really sparse. So if we go down to
something like five, we start to get this
denser population. And if we go down to something
really dense like a value of 1, you can see now we have
lots and lots of points that we can use to
spawn out our meshes. But it's very, very uniform. Like it's all the
tops of those rails. I want to break this
up a bit, so we're going to be using some
noise parameters to do that. We're actually going to use a
couple of noises to do that. So let's go ahead and go
back to our Copy Points. And off of that Copy Points, I'm
going to pull out another node. We're going to
drop down a noise, and we're going to
do a spatial noise. So the spatial noise is
actually really pretty cool. It has a variety
of different modes. We're going to leave
it in this 2D mode, and let's just go
ahead and look at the-- let's highlight that guy,
and let's visualize that. So right now, it
doesn't look like much. And that's just because
we need to change some of the parameters on this. So we're going to go ahead and
make the contrast be something like four, and then we're going
to come down here and change the scale to be pretty
big on that axis. And like I don't know,
500 there, 500 there, and just maybe give it a little
bit of rotation or something like that. So we now have this
splotchy kind of noise that's going down, and
driving our density. So what we need
to do, is we need to combine these two together,
the normal to density and the noise together. So how do you do that? Well, it's actually really easy. If you pull off this
guy and type multiply, we're going to get
the multiply node. And the multiply node is-- we'll pipe that in there. And by default, it's
not going to work. It's going to give us
this error, which is OK. The reason it's
doing that, is we haven't told it what we want
to multiply together correctly. We actually want
to multiply density for both the input for source
one and for source two. So by doing that, we
can now visualize this by hitting the
debugger on that guy. And there you can
see our points are black on the bottom and
this kind of splotchiness on the top. So if we run that through the
density filter one more time, you can see now we have these
splotchy little box bits and bobs happening there. And I'm going to actually make
this have a little more points in there than that. So something like that. Now, the final thing that
we're going to want to do, is let's-- or actually
not the final thing, the next thing that we're
going to want to do, is we're going to want to go
ahead and we're going to want to spawn off of
this some geometry. So let's just go ahead and
do a static mesh spawner like we did before. And that static
mesh spawner, we're going to actually do an entry. We'll do two this time. So we'll jump into index zero. We're going to add
into this guy a moss, and we'll just grab a moss one. They're kind of big,
we'll sort that out later. And then we'll go
into number two here. Again, we're going
to add in a moss, and we'll add in moss three. All right, so you can
see it changed there. So we have two different mosses. Now, what we want to do, is
we want these to be smaller. So to do that, we need to
modify those attributes before they get to the spawner. And that's what we did
with the roof, same thing. So if we do a TR for
this and then PO, we're going to do
a transform point. So the transform points is
going to let us essentially make these guys smaller. So we'll just map that into
there, pretty straightforward. Let's put this down to a value
of 0.1, and put this to 0.15. And now we have really
nice moss patches, but they're a little
too on and off. So what I want to do, is
just add in another noise. So we'll just pull
this out here. We're going to add
in one more noise, and this time we're going
to do an attribute noise. This is just like
high frequency noise. And actually if
we were to hit E, we can turn off the
evaluation of that node. And if we hit D on
this guy, you can see that it's just high
frequency noise everywhere. So what we want
to do, is instead of setting that to
high frequency noise everywhere, we want to
multiply that with its input. So it's going to come
in now, and you can see it's just high frequency noise. It's going to mixed in
with that other input. So that's exactly what we want. Let's go ahead and just
map that into that guy. And with that done, we can
hit the E key, the hot key to turn that back on. And we might as well hit
the D key to turn that off. And there you can
see our noise that's kind of breaking that
up a little bit more. And then of course, if we wanted
to see the effect of this, we can just hit E to
enable and disable it. So if we turn it off, that's
without the high frequency noise. And we turn it back
on, that's actually with the high frequency noise. So that's basically
how we can get moss to exist on only the top
side, with a little bit of random breakup using
a couple of noises. So the next thing that
we're going to want to do, is we're going to want to go
ahead and make a slightly more complex modular
version of this fence. All right, so we're going
to use that same PCG network and blueprint
that we set up for this simplified spline tool,
to generate the modular fence. So the idea behind
the modular fence, is instead of being one big
chunk of the rail and the post, it's going to be all
individual objects. So the post is an object
and each rail is an object. The idea is you instance
the post down the curve. That post will
have sockets on it. Off of those
sockets, we're going to spawn the rails
that shoot down the length of the curve
that create the fence rails. Now, thing that we want
to do, is we actually want these posts to
also be able to have random rotational values. So we're actually going to use
a fourth piece of geometry, a dummy piece of geometry to do
the distribution of the rails. So let's go ahead and
check out what this means, essentially I've broken
this original one chunk into individual components. So we've got the
post, and then we have the top rail
and the bottom rail. So the idea is each
one of these objects can have unique transform
attributes assigned to them, so that they break this
up and makes it look like a very random fence post. So the next thing we want
to do or the first thing we want to do, is
we want to go ahead and we want to create that
dummy piece of geometry. So in my origin,
over here, we're just going to zoom in
on this little fence post that's sitting over here. And what I want to do is, I
want to go ahead and create my helper object
or my dummy object. So we're going to go
to our modeling tools. In modeling, we're going
to go and create a box. On that box, we're going to tell
it to snap to the ground plane. We'll just drop that down
there, and we'll just hit zero and get that guy at the origin. And then we'll make it
have something like that. And then maybe make
it 120 units tall. OK, cool. So we'll accept that, that's
going to be my dummy object. So if we have that guy-- let's get rid of this one,
we don't need it in there. If we have this guy
and we hit control B, we can change its
name to something meaningful like dummy. And we can double click
on static mesh editor. And what we want to do, is we
want to add sockets on this. Those are going to be
the points that we're going to spawn off those rails. So we're just going to
say, create a socket. We're going to give
it a tag called rail, just got to give it
a name because this is going to be useful
in the PCG network. And we're just going to push
that up, and push it back like that. I'm going to hold down my alt
key and add a second socket. So we've got socket
one, socket two, they both have the tag of rail. We can save that out, and we
can jump back into our fence. So in our fence here,
if we just go back to where we were, ultimately
what we want to do, is we don't want to have all
this moss in here right away. So we're going to
save that for later. We're going to take
all of those nodes. We'll just hit C to
put a comment on it, and we'll call it moss. And we're going to slide this
guy up and out of the way, and just break that connection. So that moss is up there. What we want to do, is we want
to replace this static mesh instance there. Instead of using this
big combined fence, what we want to do, is
we want to have it use that new dummy object. So instead of
spawning off this guy, we're going to tell
it to grab dummy. And just like that, you
can see there is our post. Now, that original larger
chunk, its pivot point was in the center. So we're going to
need to offset this, so that the pivot point
will rotate around the middle of where those
rails is going to be. And again, this is easy to do. We just want to
modify that point data that the sampler is giving
us, to offset the dummy object further down the chain. So to do that, again just
search for transform points. Add that transform points in
there, break that connection, rewire it up and
the transform is going to get offset by
like minus 150 or 130, or something like that. And that's going to
essentially offset that guy, so that it's in the same spot now
as our original larger fence that we had, so cool. The next thing
that we want to do, is we want to find those
sockets and spawn off of those sockets, those rails. So to do that, you're going
to right click and search for socket. And nothing comes up, so
that's a bit of a bummer. Here's the interesting
thing, there actually is a socket tool, it's just not
exposed to the UI by default. It lives in the sample
plugins directory. So if you look at the execute
blueprint and we drag this out, you can extend the functionality
of PCG with blueprints. and if we look at this
list of blueprints, a lot of the nodes that show
up here in the left hand side are actually just built
up like Copy Points. Tons of these nodes are
actually just built up using simple blueprint logic. So if we search for
socket here, you can see that even though it
didn't show up in the UI, it actually does exist. So if we load that up and
we double click on it, let's just check out what's
going on with this guy. So essentially,
we're coming through, we're getting the sockets. We're turning the
sockets into points, and then we're making
those points into something that PCG understands. That's the easiest
way to think of it, and that's all pretty cool. So let's go ahead and
jump back into our fence. And if we actually
hit the A key on this, to evaluate what's
going on with it, right now we don't have any
static meshes added to it. So let's go ahead and
put dummy in there. And we'll add that dummy
in, and still there's no points in this data
until we type in tag rail. As soon as we put in tag
rail, you can see, oh my gosh, there's two indexes
in there, because we had two sockets on it. So that's our data
for that one socket. So what do we want to do? Is we want to get
that information for each one of these
down the spline. So again, very similar
to what we did before. We're going to use Copy Points. We drag out and
do a Copy Points. That's going to be our
source, and our target is going to be every
single static mesh that's instance down that curve. So if we grab that guy and shove
it in there, now if we go ahead and hit the a key
on this, you can see that's all of our
sockets basically going down that spline, which is
really, really cool. So now, all we have
to do is spawn out of the output of
this, a static mesh. So if we just do a static mesh
spawner and click on that guy, and let's just go into this
and give it a mesh entry. And go to index zero, and
let's just search for rail. We're just going to
grab one of these, because we're really
tight for time. Oops, not that rail, wrong one. Let's try that again. Let's grab that rail. All right, cool,
so there they are. They're shooting down, and
they're doing their thing. So now I'm going to actually
go back into the dummy here, and I'm just going to
offset these a little bit to get them know a little
bit closer to where I want. And I also want them to be
further back a little bit. I wanted to have them overlap
that fence ever so slightly. So you can see as I
move these sockets, it's updating those rails
that are shooting down that, which is super, super cool. So the next thing that
we're going to do, is just further refine this. The original chunk actually
had a little bit of slope to those guys, so that they
kind of tucked underneath. So again, we want to
modify these points before we get to the spawner. So to do that, we're
going to drag out and just search for transform
points, and add that in. And with that done, let's
go ahead and break this guy, drop that down there. And the first thing
I'm going to do is, I'm going to randomize
the rotation around this axis, so that each one of these
is a different rotation. So that makes it a look
a little more random, like each one is going to get
this random rotational value. And then we're just going
to give this like a minus 3, to give it a little bit of drop. And maybe a minus 2.5. So again, we're just
trying to randomize stuff. Maybe put this to something
like 0.3 on that guy. So now, we've got
a fence that looks kind of like that
original chunk, but you'll notice
that each one of these has got its own unique
rotational value, which is exactly what we wanted. So the next thing that
we're going to want to do, is we're going to want to spawn
meshes that are going to be where those helper posts are. So if we go back into transform
points off the sampler, the same points
we're going to grab, we're going to do another
static mesh spawner. And on this guy, we're going
to give it an entry of this. And if we just search for
fence, we're going to grab that. And with that done,
we can actually go back into this spawner
and we can hide it. Actually I think I
have to do visible. Let's do visible. Boop, all right. So there's our
little fence posts. And again like I said, we
wanted those fence posts to all be random. Like right now, it's the
same exact pattern going down that curve. So to do that,
again, we're going to just use the same
thing that we used before. We'll use transform points. So we'll just grab
that, and we'll just hold down the control
key to map that in there, map that in there. And what we're going
to do on this one, is change this to be
not around that axis. I think this guy
needs to be around Z. So let's just do
random 360 around Z. So now, you can see
each one of these has a unique rotational
value, and we're spawning off of those rails
from that dummy geometry. So the next thing that we're
going to do, is let's go ahead and hook that moss back up. So if we look over here,
we've got this guy. And we're going to go ahead,
and just pipe that into-- oh, craziness,
--pipe it into there. Now, this isn't
going to look right. It's going to do
something, but the reason it doesn't look right is
because this guy right here-- which is cool, we
want this input to be the same input
that's on the sampler. So let's go ahead and
go back to this guy, and just click that button
to map that in there. And just like that, we
now have our moss back on top of those rails. And even though they
have random rotation, the moss only goes
to that Y up vector, based on all that logic
that we built previously. So that is how I built
up the modular fence. So let's go ahead and check
out the finished result, and walk you through a bit
more of the other things that we're doing
inside of this guy. All right, we are really
quickly running out of time, so I've gone ahead
they loaded up the PCG graph for
the completed fence, as well as enabled
it in the viewport. And I'm going to walk
you through the changes in the logic that are going on. And really the area
where it adds complexity, is the fact that we are
using rail B and rail T for the rails that are
getting spun off those sockets. So that creates a little
bit of complexity, because we're randomly choosing
between rail B and rail T as it shoots down this
length of the curve. So let's go ahead and
look at the graph, and I'll walk you through it. And like I said, a
lot of it is very similar to what
we've already built. So this kind of spline
sampler, all the same stuff. The static mesh spawner is going
to be the helper static mesh spawner, that's going
to work with the socket. So that guy going
to come up here, and the sockets are going to be
that same static mesh helper. And what we want
to do, is we want to get that kind of
data set of points that are going to have the
sockets shooting down the curve for each one
of our post helpers. And that's exactly what we
get with the Copy Points. Now, where it gets a
little bit different, is we're taking those
points and we're going to introduce into them
a random value of density. So we're using this
attribute noise to randomly set values
between 0 and 1. And by setting random values
on those socket points, it allows us to have two
unique paths, one for rail B and one for rail T. And point filter is
going to be our mechanism for defining that path. So what that means is,
on the point filter, we have an operator. So if it's greater than 0.5,
it goes with the inside filter. If it's less than 0.5, it
goes with the outside filter. So we have two
unique paths here. So if it's the
inside filter, we're going to be using
static mesh rail B. Static mesh rail B is spawned
off of that socket then, and we want to copy all the
different points on that, to create our moss and all
of our little vegetation and things like that. So we're going to use our
mesh sampler for rail B, just like we did before
with the Copy Point. So it's going to copy that for
every version of that rail B that's been generated
down that path. So what that means is, if we
break this connection here, you can see half of my
fence randomly disappears because that was all the
areas that were using rail B. So if we put that back on to
complete that inside filter, we have the exact
same thing happening for the outside filter, except
it's using a different mesh. It's using rail T, same thing
for that sampling of that mesh down the length of the
spline with the mesh sampler. It's also going to
be using rail T. Now, here's where it
gets interesting. So we've got our
two unique paths that we've got, our
inside or outside path. Ultimately, we want to
create moss on both of those. So what we're going
to do, is we're going to merge those together. And if we just hit
the debug on this, you can see that
that's going to give me points that line up exactly
with those pieces of geometry. Like the rail T, rail B,
they're all exactly aligned as you would expect. And from that then,
we can go back into running our moss logic. This is exactly what
we built up before. So spatial noise, normal
density, we're filtering stuff, we're introducing noise and
we're filtering it a bit more. And then we're
going off and we're spawning all of
our little pieces of moss, that go down
each of those guys. So that is really
the only difference, is the level of
complexity that we had, because we have two
different unique paths for these two unique
pieces of geometry. Now, the other thing that
we're doing that's interesting, is we're also spawning all
these other little pieces of vegetation that
drop, but they only drop close to the post. We're looking at the distance
between the rails and the post, that's what we're using
this distance node for. So we're comparing those two. So if we hit debug
on this, you can see it's going to give
me a gradient based on how close the posts
are to the rails. And just like we
did before, we then filter that information out. So if we debug that,
you can see it's going to then now just give
me a random set of more refined set of points on those
rails close to that post. And then ultimately,
what we're doing is, we're adding in another normal. And then we're
filtering that down to give me just a few little
random points, if we zoom in here, that only exists
on those rails close to the posts on the
top of the fence, because we have
that normal density. So the concepts are
always the same. You're basically
taking points, you're running noises into them. You're filtering them,
you're trimming them down, you're putting more
noises on them. And the end result gives you
these very procedural random looking graphs, that do
some really cool stuff. Now, there's one more thing
that we're doing down here, and I'm using this
PCG subgraph that's coming off the same points
that this little fence post is. And what that PCG
subgraph does, is it comes through, it
introduces in some noise. It runs a random density filter
to prune some of those out, and then it
ultimately goes ahead and it spawns off
this little piece of geometry, which is
essentially these little twigs that come here. So not every single
post has those twigs. And if it does have
the twigs, they're going to have a random
rotation around their y-axis. So that's really all that
we've done with this. We've added in a couple
more pieces of geometry that are getting spawned off. But the big thing
that's happening here, is the little logic to have the
two different rails for our two different unique paths. And then the logic over here
for the vine drops, which is using that distance
node to only drop the vines close to those posts. So I really hope
that made sense. I know I was going super fast. I appreciate you all
sticking with me, yeah. Thank you.