 Howdy guys. All right, so in this video what I want to do was add on to the vex series on any pixel and talk about the volume gradient and the mid-pause function. And then what we're going to do once we learn those two elements, we're going to go and make ourselves a really basic flow solver. Just using those two functions, you'll be surprised at how simple it is to get a simulation that looks like this that allows you to basically simulate the flows along the terrain. All right, and so with that let's dive into the vex and get our own flow solver going. All right, so to get things kicked off here, let's let's do a little bit of experimentation or I guess I should say exploring with vex and let's take a look at the volume gradient function. This is a really useful function. It allows you to get basically the directions of a terrain, right? So I'm going to create a geometry node and call it volume gradient. I'm going to dive inside and create a new height field. And let's hide everything else just so I can focus on this guy and let's just make our terrain smaller. Something like 512, 512 work just fine for this test. Then let's go and give this some noise. So we're going to do a height field noise and you're more than welcome to, you know, make this look however you want. I am just going to leave it on the defaults because I think that looks great just for these tests. All right, so volume gradient, what does this do? So this basically gives us the largest change in direction, right? So it'll return a vector for us, but it gives us the largest change in the direction on a height field or volume. All right, the height fields are our volumes. So let's drop down a wrangle node here and let's also scatter some points. So in this case, I am going to do a height field scatter just because I want to generate some points on this particular terrain here, all right? And in this case, I also I don't want to keep the incoming terrain. I just want to see my points. Cool. And I'm going to reduce this to something like 0.1 just so, you know, we have just a small set of points to work with. And so that is basically a round 13,000 points, which is great for testing. All right, and so I'm going to do the volume gradient function inside of here just to show you guys what this does. So by default, the height field scatter node actually produces the normal for our particular points. All right, so it's spacing outwards from the terrain, which is great. We can actually utilize that information. The volume gradient is going to return a vector that gives us basically the largest change in the slope, if you will, if you want to think of it that way, of the terrain. All right, and so all we really need to do, let's store our current normal. So I'm going to say vector old normal is equal to the current at n, right? So the normal that's being created by the height field scatter here. And then what I want to do is store the gradient normal. All right, so let's do another vector. I'll call this grad Nirm like Sioux, and we're going to utilize the volume gradient function. All right, so if we go to the help for that, let's just put the cursor right into the middle of that function and hit F1 on the keyboard. You can see that it's going to calculate the volume primitives gradient, which right off the bat isn't that helpful. It doesn't really tell you much about it. And so let's walk through it here. So we just need to provide it a geometry and a primitive and a position. All right, very cool. So the geometry that we want to test against is our height field, right? So I actually need to move this stuff over here just a little bit. So I'm just going to wire in my current height field into the second input here and in our volume gradient function. Let's actually make a little space. I want to sample that particular geometry, that primitive. And the primitives is going to be zero because if you look in your geometry spreadsheet and we look at the height field here and we go to the primitive options, our height is primitive zero. All right, so we're just going to utilize primitive zero for that and the position is going to be the current position of our point. So we can just use that P since we're running over points. All right, so everything comes back, which is great, but we still see our normal that was produced by the height field scatter node. So in order to take advantage of this, we actually need to run it through a couple other things, right? So now we have the normal. If we are actually, let's just do this. Let's say at n is equal to grad norm. Look at that. You can see that they're all pointing towards their largest change, right? But they're all flat and that's not necessarily what I want to do. I also want them pointing outward. So I'm just going to put a negative symbol in front of the volume gradient function. Now they're all pointing outwards. All right. So the cool thing about this is that it's actually giving us a magnitude of the rate of change and the direction, but all only in a 2d fashion, right? So if I hit space bar 2, you can see that it's pointing outwards showing us the rate of change on the volume and giving us the magnitude or the length of that vector. Well, all we need to do is we need to actually get, you know, the slope out of this. And we have all the information that we need. So rather than just pump in the gradient normal there, let's do a cross-product of our old normal. So we're going to say old norm with our grade or gradient norm. There you go. And you can see that that actually gives us a really cool piece of information. It actually gives us, you know, that right vector that describes, you know, the vector along the terrain, right? So let's go back to our top-down view. And let's actually hit D on the keyboard and go to guides and increase the normal. You can see what it's doing here, right? So really cool piece of information, too. In my case, for this particular example, I want to produce the sloped normal. But we also do need this particular normal because then we can say at n is now equal to the cross-product of at n, so at n and the old normal. And that will give us our slope and the direction that it should be traveling in, right? Cool. So that's the volume gradient right there. So hopefully that helps out. That gives you a bunch of information about your terrain. Let's actually pump this up a little bit more and go back into our top view. So it gives us a bunch of more information about the terrain. All right, which is really useful in a lot of situations. And in the case of this video, we're going to create our own flow solver using all that information that we just produced. All right, so the next step is to look at the min-pause function. So let's let's move on to that now that we understand the volume gradient a little bit more. All right, so let's take a look at the min-pause function now. So I'm going to go and make another geometry node so we can focus on just this particular function in VEX. So I'm going to call this the min-pause node and dive inside. And this time let's drop down a height field and do the same thing. Let's make it 512 by 512 like so. And let's drop down a noise node. So height field noise node. There we go. Perfect. Now what I want to do is I want to scatter some points. So this time I'm actually not going to use the height field scatter node. I'm just going to use the regular scatter node here. All right, so let's just drop that guy in there. And you'll notice that what's happening because the scatter node is set to generate by density, the height field node is producing a density based off of the height values, right? So if I were to actually, let's drop down a copy, height field copy layer node here, and I were actually to take the height, oops, let's actually turn that off there. If I were to take the height layer and assign that to the mask layer, you can see that we're getting our density values, right? Which is being produced in the scatter node. So if I want a better distribution here, a really quick way to do that is to use the clear node. So if I do a height field mask clear, like so, and just put a value of 1 in there, you can see I'm getting a better distribution in there. You know, you could also use a volume wrangle here. You could rather than the node itself, you can always just say that at mask is equal to 1 and you get the same result like so. So let's just leave it like that. So the min pause function is a really useful function to basically snap a point to the minimum position that the point itself could find compared against another primitive, right? And so let's drop down a wrangle. So we're going to do attribute wrangle. And what I want to do is, let's just call this min pause. And I'm going to pump in the terrain into the second input there. So we can sample against that. All right. And so all we need to do is say at P is equal to min pause. And we want to test against the second input geometry, right? Or index 1. And we want to give it a position, which is our current position of the point or at P. And when I do that, I'm automatically snapping my points to the terrain. All right. So this time we ended up using just the scatter node. You'll notice that though we're getting a lot of points kind of bunched up and stuff. This is literally, it's not a true raycast, right? You'll notice that the points themselves, if I would actually raycast these guys straight up to the terrain, you would get a more even distribution. In this case, it found the minimum distance to snap to on the opposite or on the primitive that was passed in here. All right. So that's the major difference between the intersect function and the min pause function. Min pause is just the minimum distance position that it could find. Whereas intersect, you can cast ray in whichever direction and then sample that point. All right. So that's min pause. These two functions together are actually going to serve us really well in creating our flow solver. And really, those are only the only two functions that we're actually going to use. All right. So with that said, let's move on to setting up our flow solver. Okay. So let's now go and make our flow solver here. So I'm going to create another geometry node and we'll call this flow solver two. All right. And we're going to dive inside. And again, we're going to make a height field. And I'm going to make it 512 by 512. There we go. And let's drop down a height field noise node. I'm going to hit shift s on the keyboard to get my different wire designs that I like. And with that, all we need to do now is do a height field scatter. So this time I am going to use the height field scatter just because it already snaps it and comes with a bunch of other stuff like the normals and stuff like that. Let's actually just type in the scatter here. So I don't have to search through all that stuff. All right. So let's go and scatter some points like so. Now for this first pass here, I am going to put the coverage down to like 0.1 because I'm going to show you two ways to do this. Right. So one's going to be relatively slow. The other one will be a little bit faster. All right. So what I want to do is I want to loop through every single point here and basically move it down the terrain until it reaches the bottom until it comes to rest. So one way we can do that is with a for each feedback. All right. So let's get that for each feedback preset there. And really that's just a preset. Right. All it's done is it's gone and changed the iteration method to by count and feedback iteration and the block begin node is set to feedback. All right. So let's pass in the points here and get this guy going. So I just need to drop down a wrangle node. So we're going to combine both of those functions to get these guys to move down the hills here on every single iteration that we do. All right. So we're going to call this the flow algo. All right. So I want to keep this on run over points. And in here, we just want to do a vector. We'll do the old norm because we need to store that. So I'm going to get the at n for the current normal. And then we want to get our gradient normal. So we're going to do vector grade NIRM like so. And I'm going to do the volume gradient. And we're going to sample the incoming geometry for the second input here. So I'm going to get that. And I actually want to come into the scatter node actually and turn off the keep incoming terrain. And I'm just going to pass the terrain into that second input there. There we go. Cool. So now with that, I'm going to sample the primitive zero. Again, always pay attention to your primitive numbers for terrains. So primitive zero is the height layer. All right. So we're just going to sample that. And we're going to give it at p for the position of the current point that we're working on. Beautiful. All right. So once we've done that, let's do our slope calculation here. So we're going to do a cross. And we're going to do a cross product with the old norm. All right. And the grad norm, just like we saw in the volume gradient section, that gives us that right vector. And I actually need to make sure that I negate this guy. There we go. All right. And then we want to do the next one. So I'm going to say at n equals cross. And we want to cross that with the current normal, which is holding our right vector. And our old normal. And that gives us our slope that we should move in. All right. And you'll notice that the normal or the vector line that's being displayed, they all have different sizes that represents the speed that's going to travel, the velocity. All right. It's the magnitude or the length of the vector. They all kind of, all those terms basically represent the same thing. All right. Excuse me. Let's then apply that. So I'm going to say at p plus equals at n. And you can see that they shifted a little bit, right? So they kind of moved a little bit down the hill. So that's every iteration, we're going to move it down. And then we're going to resample and find the new direction. And that's what we'll get at flowing around the hills here. So after we move it, we need to make sure that we resnap it. All right. So we're going to say at p equals min pause. And we're going to sample the incoming terrain. And we're going to give it the current point position. That just ensures that it's always sticking to the terrain itself. And then finally, to make this work, every iteration, I need to reassign the normal with the old norm. Right. Because we need to make sure that we can do this, these cross product calculations on the next iteration. All right. So with that, we actually have everything all set up. So really easy, nothing really crazy there. This is really just a basic example, but it gives you really cool results. And you can do a lot with this. So now you notice that as I move the iterations, I'm moving the points down the hill. Right. And if I were to set this to something like a hundred and wait for it to actually cook, it goes relatively fast. You'll see that it's started to clump up into the little valleys. Creating these like streams and rivers and wherever they settle, you know, is where a lake would be most likely or some pond or something like that. All right. So let's, let's do this here. Let's actually, I just want to prove a point here. So I'm going to do a dollar F in the iterations like so. And I'm going to then let this calculate so you can see that, you know, as it gets into the higher frames, it goes slower. It goes slower and slower and slower. Every consecutive frame after about 15 frames, it just really starts to bog down. All right. So this is where we can utilize a soft solver. Soft solvers are a lot faster for doing this, but I wanted to show that you can actually do it with a feedback loop too. All right. So just keep that in mind. If you, if you know that you're not going to be doing a ton of iterations over a large point cloud like that, you can totally use a feedback. And then you can also put a compile block around these things, but I'm not going to get into that in this particular video. All right. So let's do the solver. So I'm just going to hit tab and type out solver. And that gives me a soft solver here. And what I need to do is I need to feed in the points into that first input and then feed in the terrain into the second input. And then I want to go and copy my wrangle node here and then just dive inside of my soft solver. And then paste that wrangle node that has our algorithm in it. All right. And so I'm going to take the previous frame data. So basically the soft solvers simulating or basically recreating this loop here, right? So every previous frame, we're getting the previous data and that's being fed into it, into this attribute wrangle node here. All right. So just keep that in mind. So that's the previous frame data. And what I want to do is I want to get the terrain. So I want to get the input from input two. All right. So input two is this guy right here for the soft solver. All right. So we just want to feed that guy in there like so. All right. Cool. And with that, if I turn this guy on here and then hit play, you'll see that we get much more performance result. All right. You can actually watch it in real time. And we can actually go and increase the amount of points too. So let's put this up to something like 0.5. Now that will make it go slower. But we still get a relatively real time view here, which is awesome. So one thing I really want to do is try to use this as kind of like a poor man's erosion simulation. Because after you work with the erosion nodes inside of Houdini, they do get pretty slow. And again, I am working with a relatively small terrain here. But I bet you I could speed it up doing our own custom stuff. Yeah, really, really cool. The last thing I really want to show here is how we can colorize this based off of speed. All right. So we are producing inside of this flow node here in this attribute angle. We are producing our velocity. Right. And so what we could do before we assign at n, right, we can do another vector, call it velocity like so, is equal to the length. And actually, I want to just make that there you go. A float. We want to equal that to the length. And we need to do length. There we go. All right. So length will give us the magnitude of our vector. So at n like so. So then what we can do is we can drop down a color node. All right. And rather than a constant color, we can just do a ramp from attribute. And the attribute is going to be velocity like so. Right. So now you can see we're getting a different color for the speed, the current speed of the point. So I'm going to set this to infrared. And let's jump up and out and let's just hit play. Look at that. So now you can really start to see how fast each point is moving. And as they get slower and slower, they become more of that bluish purplish color. But if they're moving really fast, they're more red. So pretty cool stuff. All right. So with that, those are the two different solutions. We can always set up a switch node here and pipe these guys in like so. I'm going to hit escape because I don't want that other one to calculate. And let's just switch it over to this guy. And there we go. Let's also merge in the terrain. So let's do that. And let's colorize the terrain. So you can actually use a color node and you could set it to like a darker color, something like that. Then we can merge that. So let's use an object merge node and just merge the terrain in there. Turn off the transform importing. And there we go. How cool is that? Yeah. Let's actually pump it up a little bit more. Let's do scatter of one and see what happens up here. Oh, I lifted up point one. Let's do, uh, yeah, let's do one and see what happens. Probably take a little bit of time. That's actually not that bad. So benefits of using the SOP solver, if you want to, you know, run some simulation in the SOP world. Very cool. So I'm going to let this run here a little bit more so we can cache it all out. Then it'll run real time. And there we go. Very nice. So yeah, like I said, you know, I want to do something with this here at some point. Um, and actually, you know, erode the terrain and see if I can get a better faster erosion. That's a little bit more controllable for Houdini. It'd be kind of cool. There's a lot more data here too. Anyways, custom flow solver right there using volume gradient and min pause functions. Thanks so much.