 Howdy guys, IndiePixel here, and what I wanted to do in this video was go over how to generate your own vertex ambient occlusion, alright? And this is useful not just for ambient occlusion itself, like we're not looking to really bake out high resolution ambient occlusion here. What we're doing is we're looking at ways to basically, you know, detect the distance from objects. And this is useful for many reasons in game development. Let's say, you know, you want your plants to not grow as much or grass not to grow as much, you know, where an object is occluding it because it's not getting any sunlight or any water or anything like that. Let's say you have two buildings that are really close to each other, you know, you want to be able to determine how close they are so you can maybe not place a window there kind of thing, alright? So what we're doing is we're going to learn, you know, how to generate this vertex AO only to just give you a little bit more information of how to create these more complex, you know, VEX setups and really how to basically start to integrate VEX into your workflows in a natural way, okay? So I have this box here and you can see that we do in fact have relatively, you know, speedy AO calculation going on here, alright? And I can even go and rotate the box and you'll notice that, so just do that and then let's transform it up and why, you'll notice that it reacts appropriately, alright? So we're doing the appropriate collision detection and coloring the points based off of their distance, alright? The distance of that collision, cool, alright? So let's get rid of all that rotation, there we go, very cool, let's bring this down a little bit closer and with that let's jump into actually recreating this, okay? So what I want to do, I'm going to utilize the same box here, okay? Well we're going to turn off the final result there and I'm going to create a new geometry node, alright? And this is going to be our fake AO video, alright? You can name it whatever you want, alright? So the first thing that I want to do is I want to put down some sort of grid, okay? I should also mention that I'm using 17.5, 0.173, 0.16, that's quite a version number, alright? So I just want to make sure you guys know which version of Houdini is on right now, we've upgraded from I think we were around 16.5 when we started the whole intro to vex series, so now we are at 17.5 and we now have PDG, super cool. But we'll talk about that in other videos. So what I want to do, I'm just going to leave the grid currently with its current set of points because it's enough points to work with. What I want to do is I want to go and drop down an object merge node and we're going to go get the collision object, alright? So let's just call this the collision object or objects, alright? Because we can import a lot of things into this. I'm going to set the transform to into this object so it pulls in the current transform information and I want to get the box, there we go, cool. So now we have the box and we have our grid, excellent. So what I want to do is for each one of these particular points here on this grid is I want to create a sphere or hemisphere, I should say, around this point and I want to, at every single point on the hemisphere, to shoot out a ray to see what is out in the world, what we're going to collide with. And I want to see what that collision distance is and then I want to average it up, alright, so we can find our average distance from the nearest collision object. Alright, so what I want to do, I also want to apply this to my collision object as well, so we're going to take in both objects. So I'm going to drop down a merge node here, like so, cool. Alright, so now we have both those guys merged together and then I want to give these guys some point normals because we're going to work with the point normals. Currently, if I were to take a look here, we have a bunch of vertex normals and you can tell that because they're green, alright? And there's one normal for every vertex, not one normal for every point, so that's why we have four normals there. Okay, so let's wire this into that normal node and I'm going to convert that to points and we can leave it just like this, it's totally fine. We actually do want just the average normal because when we go and create the hemisphere around this point, I want it actually kind of pointing it downwards, you know, so we want to average all the normals here. So this is going to work out perfectly. So next step here is to drop down a for each point loop, alright? Now I'm just using this for each year to make it a little bit easier, alright, in terms of working with the calculations here. What we would really actually do is drop down a wrangle node and just do the loop inside of there, but this will make it a little bit more visual for everybody. So if you're still relatively new, this will make it a little bit easier. It makes it run a little slower, but it'll just be easier to understand. Okay, so now what we need to do is we need to create that hemisphere. Okay, so I'm going to drop down a sphere node like so. Alright, let's focus on this now and I want to turn it into a polygon. Alright, and I also want to then clip it because I don't need the whole sphere. Alright, we're just going to clip it right on the y-axis there. And the reason for that, let's actually just take a quick second here and take a look here. The reason why I don't want to have a sphere of normals or you know ray casts around this every single one of these points here is because if I had a sphere it would be looking below this grid, right? And all it would do is return black because we're not really seeing anything. Alright, so we'd really mess up with the calculation. What we want to do is we want to take the normal direction, alright? We want to copy one of these hemispheres to each one of these points using that normal direction as the main direction to cast the rays towards. Okay, hopefully that makes sense. Alright, so what I want to do with this is I actually want to pull this up a little bit as well. Alright, we don't want completely flat normals here because we don't want it to collide with the grid, right? So if I had a point here it would actually just collide with the grid and again just give us black. So I want to actually just pull this up a little bit. So let's do something like point one like so. I think that's going to work. And then let's create a normal here and again we're going to be working with point normal, so not vertex normal, so there we go. Now I just have one normal for every point. Awesome, and you can see that these these points here are these normals except for this little guy right there. I should probably pull this up a little bit more. We can also, instead of using the polygon, let's just use a, there we go, polygon mesh. That way we get a nice grid of points instead of this kind of random set. We're not random, you know. This will actually work out a little bit better for us. So let's actually drop this down back to point one. There we go. And then what I want to do is drop down a transform node like so. We're going to scale this down really tiny. So we're going to do something like point zero one. Alright, and what that does is it provides us all of the raycast directions. Alright, so this is what this is what really makes this really easy for us to do. We don't have to do, you know, the hardcore ambient inclusion calculations. We can just kind of fake it with a really simple solution. Alright, and this is really good. Like I've been using it for like foliage placement and stuff like that and like grasses. There's a really quick way to just, you know, implement this into your HDA without having to use any of the really complex stuff because really I'm just testing distances. Okay, so we made that really small. So now what I want to do is I actually want to do the collision detection. So for every single point in our collision geometry here, alright, so for every single one of these points I want to copy a sphere to it. Okay, so we're going to do a copy to points like so. So we're going to copy this object to every single one of those points. Alrighty, and let's just wire this in. We could see the result of that, meaning that we get a little, you know, fuzzy. It's kind of hard to see here, so the better way to show this is to hit D on the keyboard, go to the guides, and it will scale this normal down to 0.01 as well, just so we could see about it. You can see that our hemispheres aren't actually pointing towards normals and that's pretty easy to fix in this case. We just need to rotate it by 90 degrees in the X. Alright, so let's just drop down another transform node there, and let's just rotate this 90 degrees, and there we go. So now we have one of those little hemispheres copied to every single point and let's just make the, let's try 0.1, there we go, let's try 0.05, there we go, that's that's going to be fine for now. So now we have this radius of ray casts or directions that we can ray cast with. I'm also going to go and just tie the rows. So let's do a copy parameter and we'll do a paste relative. So copy these two together, because the more points you have here doing the the test, it's going to slow it down. So we're going to try to find that maximum amount of points that we really need to get a good solution. So I think this will work out for us. I think actually I did six and that looks good to me. Cool. All right, so we're going to go with that. Sweet. So now for every single one of those particular spheres or those hemispheres that we're working with, what we want to do is we want to cast out into the scene. So I'm going to drop down a wrangle node here. Alrighty, so let's pump that into an attribute wrangle and we'll do the calculate distance. So this means that we actually need to get the collision geometry. So I need to collide with everything. So we actually want to get that from this normal here, all right, because this is where we merge it or we could do it from the the merge node. I'm going to just use this guy right here. So we'll call this the aridge geo. All right, and so to do this I'm not actually going to just drag and you know drop this into this guy right here, because that just makes for a messy network. What I like to do is drop down the object merge node and I'm going to then call this get aridge geo. Okay, and I'm going to feed that into this input. So this is input one, this is input zero. Okay, so with that what I can do is I can raycast now. Okay, so I can say for every single point, all right, remember this attribute wrangle is set to run over point. So it's like a loop itself. So we're going to run over a single one of these points here, okay, and we are going to see if we collide with anything in this original geometry. So to do that, let's actually create a new float first. We'll call this our max distance. So this is a max distance that we're going to cast out into the world, okay, and we're going to expose this as a channel or a float channel, so chf, we're going to call this max dist. So this just allows me to actually change that value. So I'm going to default it to one. So that's one unit inside of Houdini, okay. And so then what I want to do is I want to set up all my local variables here. So I'm going to say vector out pause or we could say hit pause, and I also want to do out uvw, all right, so for the for the uv information about where we hit, okay, and with that we can now say int hit, we're going to do our intersection test, okay, so I've gone over this before in one of the previous vex videos. So we're just going to do an intersect. So we're going to do intersect, cool, and we want to intersect with the geometry coming into the first input here, okay, but we're going to use the position from the current incoming point for input zero, so at p, okay, and I want to get the normal, or I want to use the current normal that we have in here, all right, coming in from input zero. So we're going to say at n times our max distance variable. Then we want to output that into hit pause like so, and out uvw, cool, so what this is going to do is it's going to actually turn the primitive number that we hit, okay, so that means that if hit is equal to negative one, we didn't hit any primitive, because hit could equal primitive zero. So we can test for that now, we can say if hit is greater than or equal to zero, that means we hit something, else we didn't, all right, cool, so if we did then what I want to do is I actually want to find the actual distance between our hit position and our current position. So we're going to say float dist is equal to our distance between at p and max distance, all right, so that's the max distance we can look out into the world. All righty, so then we could wire that in here and we could take a look and see if anything's changed, and it hasn't because we actually haven't changed any of the visuals here, all right, so we should probably go down to the bottom here. This is where we're going to actually start to see some collision happen, all right, so what we need to do is we need to pass that value, that distance value, all right, into our color, okay, but currently we're just getting the distance, so I mean this will actually work because our current distance is one, but we're going to have to modify this and say we're going to divide it by our max dist as well, because I really want to normalize it, let's say I set my max distance to 10, I really just want a value from zero to one, that way I can actually go and assign, so I'm going to say at cd is equal to dist, like so, and we're not seeing anything because we actually need to go and assign our original geometry, we're currently, I'm not passing any geometry into this particular attribute wrangle here, and so I actually need to get the original geometry, so I just need to type in dot dot, a ridge, geo, there we go, all righty, and we're going to say none, all right, so now we're colliding, so let's just make sure, all right, cool, so now we're testing that and let's reset our cache pass here, and you should see that we're now starting to get some colorization differences, all right, and so if I were to go and change the max distance here, all right, let's test this stuff out here, let's actually just increase this a little bit, maybe we do like 0.5, there we go, so now we're starting to get some changes in our actual color, so what we need to do is we need to go and average that out, so I'm going to drop down an attribute, it's kind of hard to see right now, so what I want to do is I want to say attribute, promote, all right, so I'm going to just promote this from point, because currently we're working with points, so I'm just going to send it to primitive, we're going to average it out, all right, so we're going to take our color, we'll average all that stuff out, and this guy's got nothing because, well, it's not colliding with anything, cool, all right, but we start to get, you know, darker primitives down here, all right, cool, so now what I want to do is just drop down another attribute wrangle node, and I want to take the original point, all right, so this is the original point that we're using, all right, and I want to pump that into my first input, take the average color, all right, and we're just going to transfer the color, like so, all righty, and we'll pass that into there, like so, and so we're going to say at cd is equal to point from one, we're going to get the cd attribute and the current at ptnum, because the point numbers are the same, basically, and actually I wanted this to be, so actually I copied it over here, so I wanted this to be point, actually we need to promote it to a detail, let's do a detail here, there we go, all right, so now we've got our detail right here, and this will have the the different color value, so I really just need the first channel, so what I can do, sorry about that, what I can do now is say detail from point or from geometry one that's coming in here, I want to get the cd value and we just want to get the first channel, all right, and then I believe I also put this into a power just to kind of ramp it up a little bit by three, like so, there we go, and that should be that, all right, so if we take a look here, our point should be a little bit darker down at the bottom here, it's really still hard to see, so let's actually drop down another wrangle, so I'm just going to really quickly assign the original geometry, so I'm just going to copy this guy here and hold down alt and left click and drag, this is the original geometry, so I want to assign all the point color values that are here onto this guy, so I'm just going to pump this into the first input and this into the second output or input and here's the expression that I used, all right, so for every point number in geometry input one, I'm just going to pass over that same value like so, you can see I'm actually getting a weird result and let me actually just do something here really quick, let's just say that at cd, so if we hit something we're equal to zero, there we go, that's actually what I was looking for, so let's just leave it there for now, all right, so from there I just did an attribute blur, so attribute blur and I left the blurring iterations on one and really we just want to blur the color and then I just used the step size to control that kind of fall off there, all right, so now if we have more geometry in our particular grid, so let's actually do this, let me copy this parameter and put that in there, all right, so there we go, so now we're going to get a different result, so you can see that now we're occluding the geometry, so what I want to do is just move the box down a little bit, there we go, cool, all right, so you can see also if I go and reduce the amount of geometry I have, while we don't get as accurate of a result, the speed is a lot faster and we could speed this up even more if we really just put everything into a single wrangle node, all right, so we don't really need to be using that for loop, so with that, that is how we do custom vertex with the vex, I know there wasn't, you know, a ton of vex in there, nothing that was new, but what I really want to do is start showing, you know, practical uses of all this stuff, you know, it's fun to do these little tiny examples, but this has a real practical use, like I said, I've been using it for foliage type of stuff, just to indicate where foliage shouldn't grow kind of thing, so it's something that that I've been using at work and so I thought I would show you guys, all right, thanks so much, talk to you soon, bye.