Introduction to PCG Workflows in Unreal Engine 5 | Unreal Fest 2023

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[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.
Info
Channel: Unreal Engine
Views: 57,980
Rating: undefined out of 5
Keywords: Unreal Engine, Epic Games, UE4, Unreal, Game Engine, Game Dev, Game Development
Id: LMQDCEiLaQY
Channel Id: undefined
Length: 56min 15sec (3375 seconds)
Published: Thu Oct 26 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.