 Howdy everybody, this is IndiePixel here, and I am happy to bring you guys part five of the intro to Vex series, sorry for my delay. I've been working on some client projects, so didn't have time to do any YouTube videos for the last few weeks, so I'm back, and I'm gonna start pumping these guys out for you guys. So in this video in part five, we are going to cover something a little bit more advanced, you know, it's just the next step in your Vex adventures, if you will. So what we're gonna do is we're gonna learn about how to find neighbors and how to use PC Open. So let's talk about neighbors first. So what I wanna do here is I'm gonna show you guys how to find the neighbors of a particular point that you provide, and in this case, we're just gonna assign some point colors to them so we can identify them just for learning purposes. So once we do that, then we're going to figure out how to use that same sort of technique to find borders on a particular piece of geometry, and in this case, it actually works better when you have organized points. We'll see in the last example in this tutorial how the borders don't necessarily work, so we'll cover that when we get to it. And then finally, we're gonna take a look at how to use PC Open, PC Iterate, and PC Import to process a PC file. It sounds like a point cloud file, right? But in this case, we can use that point cloud file to process points on a piece of geometry using VEX, okay? So then we're gonna close out this particular tutorial or this video, and we're gonna learn how to actually create a border fall-off based on the border of a piece of geometry. And in this case, I just decided to create a simple like land mass if you wanted to create, you know, a stance for some sort of terrain in your game. So in this case, we have a digital asset here where you can control the remeshing. You can control the max points to reduce or increase that fall-off. You can change the blurring amount. So it's kind of like a fake erosion, really. It just blurs everything, just smoothing the whole thing. And we can control the height as well, like so. But really what the main concept that I wanna show off is this border selection. How do we create this fall-off from the border to the inner part of the mesh and for any type of mesh as well. So it's super helpful. And especially when you're doing terrains like this. So let's go over and learn some of the basics first before we jump into this particular example here. So I'm gonna jump back out and let's go and create a new geometry container here. And I'm just gonna call this neighbors. Because we're gonna cover the neighbors first. All right, so let's get it grid, like so. And we'll leave the rows and columns the same, but I am gonna hook up the relationship here. So we always keep it square, like so. Okay. So what I wanna do is first just identify what the neighbors function inside of X does. Okay. So I'm gonna drop down a wrangle node here. And what I'm gonna do is call this neighbors, like so. And it's not actually not too hard, but what I'm gonna do is just walk through how it works for you guys. So the first thing I want to do is create a new array. And I'm gonna call this the nays for neighbors, just short for neighbors. And it needs to be an array. So we have to put those two brackets next to it. Because it's gonna fill it with a bunch of points. So all the neighboring points. So basically the concept here is if we have a point right here, I wanna find all the neighbors. So it's all the points that are actually attached. So it's gonna be these four points here. Okay. And so in order to do this, what I'm gonna do is just type out neighbors. And you'll notice if we go to the help, so let's pop open the help here. And let's type in neighbors. And we want the vex. We want the vex version here. So you can see in the help, we want an input number. So it's the points that we want to process. And I actually wanted the neighbors. Hold on one second. There it is, neighbors. All right. So it wants the input and a point number. So this works out pretty well for us because let me hide the help here. What we can do is just give it the current geometry, which is input zero, right? And that's that first input there. And then we can give it the current point number. So at PT num, like so now, that will give us for each point, the amount of points that are next to it. And it will also store the point IDs for all those points. All right, so that's what this is returning. It's returning, let's go back to that help there. So it's returning an array of integers. Okay. So that means we have all the point IDs of all the neighboring points. So for this particular point, we're gonna get this point and this point because this point isn't connected. This is where the PC open method comes into play because what if I do wanna find that point within a radius? So if I have this point selected, how do I find all the points within a radius around that point? So it's two ways to find points in a mesh. So we'll cover that PC open here later. But for now, let's say for int i equals zero and i is less than, and what we wanna do is we want to say that i is less than the number of points that we have inside of this integer array called nays. And in order to do that with an array inside of x, we need to use that len function, short for length. So we'll get the len of nays and then iterate. So i plus one, or i plus plus. All right, so now we have a loop. So we're looping through all those points. All right. And what I wanna do is I want to say I wanna set the color of each one of those particular points. So in order to set the color of the particular point that we currently have selected inside of this nays array, we need to utilize a function called set point adder, or atrib. And so what we wanna do is we wanna set a color. So in order to do this, what we'll say is set point atrib. We're gonna say geo self because we wanna process or we wanna set a point attribute on this particular set of geometry itself. And then we wanna set the color attribute. So that's cd, lowercase d. The point number is gonna be the current iteration that we're on. So it's gonna be nays, i. And then the value, it's going to be, let's just color these guys red. So that's red. And then we'll set that value like so. And that turned the whole thing red. So let me actually get rid of the set value here. And that's because, well, we are setting all of the points to red right now because what we're doing is we're going through every single point in this particular loop. So what if I wanted to set a particular point? So what we need to do is we need to actually specify a particular point number. So I'm gonna call this the point num like so. So I'm gonna create a new parameter here and it's going to be an integer channel. And I'm gonna call this point num like so. And instead of using that apt-pt num, I wanna use point num. This is a value that's gonna be provided to us by this channel that we create. So now you can see as I move this along or increment the value there, I'm selecting the points that are connected to this particular point. And what we can do here also is set the point attribute for the current point that we're on. So geoself, cd, and we want the current point num that we've selected and we want to do it as green. And again, we can do that set. So you can see that you don't necessarily need the set. But if you do look at the help over here, it does like to have the mode set, even though it still does work. I think by default it is just setting it. But it's good practice to get into setting the mode. So there we go. So now as I increment through this particular piece of geometry, I'm getting the current point, which is being set to green. And then I'm finding all of its neighbor points, which are being set to red. So imagine you can start to use this to process values on all of the points of this particular geometry inside of its own loop. So let's say you wanted to set up some sort of like smoothing type of operation, or you wanted to do some image processing on the colors of the points themselves. So you could blend all the colors together and blur it, or you could smooth out the height values of the particular mesh. This is how you would start to go about doing that. Okay, and it's just really good practice with Invex to start getting into some of these more complex operations and learning about these other methods that we have neighbors and set point attribute. Okay, so now that we've got that, let's take a look at setting or finding the borders. So we'll do another attribute wrangle node and call this find borders. So again, what I wanna do is I want to loop through all the points and find all of the neighbors for each point. So in order to do this, I am going to get the neighbors. So again, that's an array of points and we're gonna utilize that neighbors function. And we're gonna give it the input of zero because that is where we're inputting the geometry that we wanna work on. And in this case, I do wanna use that PT now because we're gonna loop through all of the points because you'll notice that some points only have two points or three points. So let's take this particular point right here. So let's find the point number. So point 21 right here. So point 21 only has three points connected to it. Whereas if we look at point 20, it's got four points connected to it. So what we can do is we can say, well, if you only have three points or maybe two points, so anything less than four, you're probably aborted. All right, so let's take a look at that. So let's go through and we'll say if, nays, actually we need to do that len function again. So it's nays. The length of that is less than four, the more border point. So what I wanna do is I want to color it. So we're gonna use that set point atrib function. And we wanna do the geo self. That's this piece of geometry that we're working on. We wanna set the color. And we wanna give it the current point number. And that's this particular point that we're working on. Okay, so it's this PT num right here. Cause all we're doing is we're saying, well, if this particular PT num has less than four neighbors, then you're aborted. And because we're running over points, this is basically a one big loop. So for each point, this code is gonna run, okay. So we're gonna give it at PT num. And we're gonna set the color to blue. Cause I've already used all the other colors. Let's do a set. Semicolon, we'll check it out and boom. We now have the borders of this particular geometry. Now this works really well on an organized piece of geometry. It works really well on a grid. You'll see here when we get to the fall off, that doesn't work so well. You can still find it, but what you'd have to do is actually look at edges instead of points. All right, and I'll cover that in a later tutorial, but I just wanted to start to introduce these particular functions to you guys in this intro series. Okay, all right, so that's how you find connected neighbors in a piece of geometry. So now let's actually find points based off of a radius that we defined. And in order to do that, what we have to do is we need to utilize the PC open, PC iterate, and PC import functions. So I'm gonna drop down a wrangle node over here. All right, and we're gonna call this the PC open. All right, and what I wanna do is I want to iterate over a bunch of points that are within a distance to a given point. So let's turn on our point numbers here. So let's say I pick point 60, so let's do that. Let's say that I want to provide a point number. So we're gonna just call this BNT num, and that's gonna be equal to CHI, because we're just gonna allow a user to define the point number. And we will create that channel. So currently we're picking point number zero over here. So I'm gonna set it to 60. All right, so that's gonna set the point right here. All right, so what I wanna do is I wanna create another integer, and I'm gonna call this handle. And we're gonna say this is equal to PC open. And what I wanna do is first go and just look up that help, this is what I always do. So whenever you're learning something, you wanna utilize the help that we have here that SideFX provides. So PC open, what it wants is either a file name, which is a string, or an input, which is an integer, a channel, a vector, or a string, a radius, and an integer of max points over here, okay? So what I'm gonna do is say zero for the input, for the channel I'm gonna find the position, so P. And we're gonna utilize the position of the current points. So in order to get the position of the point that we have selected, we need to provide another variable here, and that's gonna be a vector, because we want the position. Everything's gonna be based off of the position that we provide. And we're gonna call this the P pause. And that is gonna be a point method, because we wanna get the position. So from input zero, I wanna get the P position. All right, so if we type in point over here for our help, there we go. We want the string geometry or the op input, which is zero in this case. And we want the string attribute name, which is P for position, and the point number. So let's put in that P and T num. There we go, and that gives us the point number. So now I wanna provide that, so we're gonna say P pause. Whoops, there we go, P pause. So let's go back to our PC open help, there we go. So now we have the position, let's give it a radius. So this radius is going to be based off of a channel as well. So I'm gonna just give it a CHF for a float channel, and call this the radius. And then I wanna do a max points, and that's an integer. So we're gonna do CHI, and call this max points, just to keep everything simple. And with that, we are now going through the current selected position. So we find a point that we wanna use based off of this channel right here. I'm also gonna go and create the other channels. So these two guys, radius and max points. I'm gonna set the radius to one and max points to five for now. All right, so again, we're finding the point number that we want to base our search off of. We're finding the position of that point number that we selected. And then we're opening a point cloud file and storing it inside of this handle. Now this handle is the ID or the integer value of this particular file. So we can use that in the PC iterate and the PC import functions. This is needed by those functions. So PC open is where you start when you start working with these point cloud files. Okay, so now that we've got that information up and running, so let's do a while. And we'll say PC iterate, like so. We'll provide it the handle is greater than zero. All right, so we're gonna check out the help on this one to figure out why this works right here. So let's go back to the help and let's do a PC iterate. All right, so the PC iterate takes a handle. So we created that handle because we opened a point cloud file. So now the handle has information in it. All right, and you can see right here says the function returns one while there are points left in the iteration loop or zero when there are no further points. So because we have a radius and we have a set max points, what's happening here is we're putting a bunch of points into this point cloud file and all of this is just being stored in memory, okay? And so that file now has a handle. So we have a link to this particular file and this file contains all these points that were found within this radius and this max points channel. So what we're doing is we're saying, okay, or what PC iterate is doing is saying, okay, I'm being given a file using the handle and for every point, I wanna do something inside of this while loop and when I run out of points to process, I'm gonna return zero, which would break this while loop because we return one until we're out of points and then when it's out of points, it returns zero. Awesome. So now what we can do is we can say, well, I wanna actually get the point inside of this file because the PC iterate literally is just, it is looping through the points but it's only telling us when we have no more points to loop over. So what we need to do is we need to say, we need to get the current point. So I'm gonna create a new attribute or a new variable called curve point and I'm not going to assign anything to it because that's where the PC import comes in. PC import, let's take a look at the help here. So PC import, all right, so this is going to return a point inside of that point cloud file that we opened with PC open, okay? So what we need to do is say PC import, we're gonna give it the handle, so that's the file, let's give it our handle and we wanna do the string channel name. So in this case, because I just want the point number, you can see down here there are a couple of special channel names that we can import because these are most likely the more common things that you're gonna wanna do when you start working with these point cloud files, okay? And so I am going to say that the channel name is called point number because I really just want the ID, the current point that we're on while looping through this PC iterate function. So I'm gonna say point dot number. And then finally, I wanna store that value and because here in the help, whenever you see this ampersand right here, that means that what it's gonna do is it's gonna store the value into that particular variable that you provide it. It basically, think of it as, it's exporting the value from this PC import into this current point variable or whatever variable that you assign to it yet. So what I'm gonna do is say current point and now what it's doing is every single time we're running through this, it's storing the current point ID, the point number into this variable right here. So now we have access to it. So what we can do is we can set an attribute on it. We can set any attribute that we have. In this case, I'm just gonna use color because it's visual and it's easier to see on the video. So we're gonna do a set point attribute function and we're gonna do that geo self again because we want it on this particular piece of geometry. So let's take a look at the help again. All right, so the string name. I wanna set the CD, right? And then I wanna set that point number. Now that point number that we're currently on is this curve point. So we can copy that and paste that right there. All right, and we wanna give it the value. So in this case, I'm gonna color all these points green. So I'm gonna use those, whoops, these brackets right here and we're gonna say zero, one, zero. And we'll set the mode to set and close out that function. And I put that in the wrong deal, there we go. So now you can see we are selecting the points that are within that radius that we currently have selected, radius of one. All right, so I can increase this and then increase the amount of points also and then decrease this. Oops, went way too far there. All right, so that is how we now start to select points that aren't necessarily connected to one another but are within a distance of each other, this radius distance right here and the max points, right? If we only have this down to something like five, then even if we have the radius at four, it's only going to give us five points because we told it to only look for the five closest points. So if I put this up to something like 10, we get the 10 closest points or 20. We start going out and we can just start adding this and increasing these values. So if I were to, let's say increase the rows and columns on this, let's turn off our points and point numbers there and let's change the point number. You can see now we're getting a better way of selecting points that are within a radius. So you can just leave the radius at something like 10 and then just control the max points. There you go. And that is how you use the PC open, PC iterate and PC import methods inside of X to search for stuff that's around a particular position in space. Okay, so now that we have all that information about these two types of ways of searching for points around a particular position or point, let's take a look at a practical example of how we can utilize this in our everyday workflows. So in this case, what I wanna do is I want to create a falloff based off of some random shape that I create, not a grid. I wanna create some random falloff and give myself the ability to control that falloff. So I wanna be able to either increase that falloff or decrease it or decrease it and then just change that blurring amount. Okay, so it's a combination of X and the nodes inside of Houdini. So let's go and recreate this. All right, so I'm gonna create a new geometry container here. Turn off that previous one. And let's jump inside and let's create a curve. I'm gonna drop down a curve. I'm gonna go to my top view here by hitting space bar two and hit enter on the keyboard and that puts me into an edit mode. So in this case, the grid numbers are actually very useful to us because when we use the PC open, you remember that we're using a radius, right? So a radius of one is pretty big in this particular. That's one meter, so it's three feet, right? Roughly three feet. So if we create a shape, what we wanna do is try to make it maybe somewhere around two. I mean, I just wanted to bring that up because the grid numbers do help here in terms of understanding how the PC open is working. So what I wanna do is actually delete the values that I put in there already. Okay, so I wanna create some random shape. And I use this particular technique when I create terrains because I find that a lot of terrain editors, they're, well, awesome, like World Machine, you know, and Map Magic for Unity and Geo World, I believe it is. They're all really great at creating that awesome-looking terrain with all the erosion and the colors and stuff like that. And they give you a lot of ways, especially World Machine, they give you a way to stamp down shapes, right? To create that height map, that initial height map that you go and disturb with noises and erosion. But when you're designing a game, I really do like to be able to design my terrain using just very simple stamp shapes. And then what I do is I convert my whole level that is in this very, very basic height map. And then I process it through all the terrain editors, like Map Magic or Gaia for Unity. Okay, so this is what I usually use this technique for just to give it some context. All right, so I'm gonna make this shape close, this curve, and reverse it as well in this case. Okay, so what I wanna do is I'm gonna leave it as a polygon, it doesn't really matter right now. So what I wanna do is remesh this. Because currently, you can't, if I were to just use this to try to find a border in a fall-off value, I don't have enough points to process that. So I remesh it and control this target edge length for the resolution. And that will give me a better way to create this border fall-off value. So let's give it some more points there. That's pretty good, just like that. All right, so the next thing that we wanna do is wanna find the borders. So we could go in and use that attribute wrangle, that find borders technique that we just did. So if I come in here and what I wanna do is create that nays array and use the neighbors function or method, give it the current input geometry, which is zero. So the first input here. And we'll do the at ptnum. Because I'm gonna loop through every point and see if, or see how many other points are connected to this particular point that we're looping through. Because again, we're running over points. So every point, we're gonna run the code that is inside of this attribute wrangle node. All right, so we're gonna say if the length, or length, but it is length inside of Houdini here. If that length of nays is greater than, or let's say is less than four, then we're a border point, right? So we should be able to say, we'll set the at-trib or set the point at-trib. Here, and again, it's geo-self. And we're setting the color. And then we wanna give it the point number. So that is the current iteration that we're on. Well, actually we wanna give it the current point number. Yeah, so at ptnum. And we will set it to a value, we'll say set. And you'll notice that we're only getting a few. So let's say we're less than, let's say five. Click out of here. We're almost getting all the points here. The other thing you can do too, instead of this, let me comment this out here, is use the set point group. So we can say set point group. I think you guys like this. So let's check out the help for this here. All right, set point group. So we want the geo-handle, which is zero. The name, which is gonna be border, let's say. And the int is the point number. So that's gonna be at ptnum. Okay, so the value is gonna be one. And our mode is gonna be set. So you'll notice that if the group does not exist, it will be created. All right, so instead of setting a point attribute, we're setting a point group. So there's another way you can set this here. So there we go, clicked off of it. Now, if we turn on our groups, our group display, you can see that we almost have all the points there instead of border. But there are a couple of points here that are connected. And that's because this mesh is triangulated, right? And so we have, in this case, one, two, three, four, five. So it's not less than five. But if we go to six, though, let's see how this works out. We start to get other points that are internal. So unfortunately, that's not gonna work for us. In this case, what you need to do, in this case, is look at the primitives and the edges around us. But I'm gonna save that for another tutorial because that starts to get a little bit more complex. So let's get rid of this set point group here. And instead of trying to find the borders with the attribute wrangle, we can use a group node and just set this to border. Because I have $OS in my group node here for the group name, it's just gonna use this name for the group name. Hopefully that makes sense. And instead of using that base group, I'm gonna say include by edges and say unshared edges. And set this to points. And you can see now we get all the edges or the border points here, so much easier. Okay, so with that, what we can do is then go and drop down a color node and colorize, let's call this initial color, and we'll set the border points to black. Perfect. So now what we wanna do is I wanna loop through all of those border points. And I want to find all of the points that are within a distance. So not necessarily in neighbors, I wanna find everything within a distance. So I'm gonna use the PC open technique for the search. So let's do an attribute wrangle and we'll call this the border search or fall off search, how about that? All right, so in this case, since I already have that border group created, I'm gonna go and select the group of the points that we wanna run over. Okay, so we're just gonna loop through all those points that are set to black, all the points that are in the border group. And what I wanna do is say int handle is equal to PC open. And we wanna do the initial. So this is always why I like to have the help open because it is actually hard to remember all this stuff. Just have to top your head. It gets a lot easier the more you do it. But I do still like to have the help open while I'm doing these things. So the channel is gonna be the position and we wanna take the current point, so at P. And that works because we're only going to loop over the points in this border group. And then what I wanna do is define that radius. So again, I'm gonna create a float channel, call it radius, and then I'm gonna create an integer channel. And call that max points like so. So now I have the handle, awesome. So we're gonna do the while loop and wait for the PC iterate method to complete. We'll give it the handle. And we'll say if it's still greater than zero, meaning it still has points in the file, we're gonna keep running over all the points in here. So again, I need to create that integer for that's gonna hold the current point number. So cur pnt num will work. And what we can do is we can say PC import. So I wanna get the point. All right, so let's put in PC import here. Very good. And we need the channel name and the handle. So handle, channel name is gonna be our point dot number. Remember that's a special case for this particular function, point number. And I want to store the value into that cur pnt num variable that we created earlier on. Okay, so for each one of those points that we find, we wanna color it black as well. So we're gonna say set point atrib. We'll say the geo self. We want the channel that we wanna set. So that's the color. So c small d. We want the point number. So cur pnt num and we wanna set it. Well, first we wanna set the color. So 0, 0, 0, and then set the mode to set. There we go. Let's create our, so we'll create the radius and max points. And you can see now we're getting a nice fall off. And we can basically fall off all the way into the middle. Change the radius a little bit more. Max points. So you might be asking yourself, okay, so now how do we smooth this out? Cause this is still not totally working here. So I'm gonna leave this to a radius of two because that is our max width and depth. So in order to smooth it out, a really quick and easy way is to use the attribute blur. So I'm just gonna feed the results of this search into the attribute blur. We'll just call this the blur. And what I wanna do is blur the CD, the color. There you go. And you can make that more refined. You can play around with these values. So that becomes a combination of adjusting these values and the blur values. And that's literally all I did. Nice, pretty cool little effect there. There you go. And that's how you can get some really, really accurate, smooth border fall-off colors. So with this particular information now, what you can do is we can create another attribute wrangle and simply add some height to it. So height, like so. And what we'll say is we'll say at p.y plus equals at cd.r, something like that. And there we go. Now we have some terrain type of thing. And you can change that smoothing, which feels like a fake erosion, but it's super fake because it's just doing it completely over the entire surface with no respect to water, slow and rock hardness and all that stuff. Then we can change that fall-off. There you go. So just a practical example of utilizing the PC Open. You could do this with the neighbors as well. In this case, it would work pretty well. But I'll leave that up to you guys. I think you get the idea. The other thing that we could do is just pass this through like a point bop. So if I drop down a point bop here, all right, we'll say height. Or we can call it terrain filter. There we go. Okay, so we can take that information and pass through something like a Voronoi noise. So we'll give it the position. And what I will do is create a vector to float. You could do all this in Vex as well, but this video is starting to get a bit long. So I'm not gonna necessarily show that. All right, so I'm gonna take the color vector, split it, I'm gonna multiply distance one with the red color there. And that will be our new height. So I'm gonna do another vector to float. Feed in the original position. You could also use a displaced by now because, yeah, all the normals are pointing straight up. Whatever, we're just gonna use this. And I'm going to add the current height so the Y value with our noise value there. And we'll just put that into the P. And I do need to actually do a float to vector. There we go. So this is our new Y. There's our X and our Z, our originals. And there you go. So now we have a cool way to make terrain stamps here instead of Houdini. There's lots of cool applications here. So you do something like that. Maybe offset it a little bit. There you go. So you're starting to get something more mountainous. All right, not too shabby. So then we can go back up to the blur. Let's play around with some of the values here. There you go. Or we can just really tighten it up there and make cliffs or something like that. Or just blur it a little bit. Then we can come up here and change that offset. So what I would do is I create lots of different types of these stamps and then stamp it around to generate a terrain that is highly iteratable. If that's a well word. You can direct it really, really well because instead of your terrain being controlled all together with a bunch of masks and over one big terrain geometry, all you need to do when you're in your initial design phases is stamp around a lot of these particular land masses that I like to call them or mountain stamps. And it helps you to design your terrains in a much more designer friendly way, I think at least. So what I would do is I'd stamp a bunch of these around, convert it to a height map and then apply that to my terrain editor and usually mask out things like the roads or where certain villages or something like that would take place and then run the erosion algorithms on that and that usually gives me a pretty good level. I'll probably make a tutorial about that here pretty soon. I am working on a new flight simulator that will, inside of Unity that will take advantage of tile based terrains and it's just taken me a long time to actually finish it all. It'll be a bunch of foliage and trains and trees and stuff like that and how to get it all into Unity and goes over the flight physics too. So anyways, I'll save that for later. So that is how we do that with PC Open and neighbors and arrays and set point attribute and set point group. So all this will be available up on my gum road. So for free, so feel free to download it and just use it for a reference. Thanks so much.