October 26, 2020

Procedural Terrain | Chapter 3 - Clip 1


Welcome back to chapter three. Last time we ended with the created tunnel curves and had an initial shape for the tunnels as well. In this chapter, we are going to add more detail to our terrain. And with a finalized landscape, we do the split again, and then use the final tunnel to do the boolean operation.

In this clip, we are using the basic tool set for height fields. The thing that stands out though, is that we are using what we created before to direct what we want to add something. So first let's grab the terrain that we have selected either from inside or outside of the system. I want to do two things here.

First, I want to smooth in the area where the rail goes over flat terrain. That's where the system will place towers. On the one hand, it can only do that if the terrain allows it. And on the other hand, it makes sense for that area to look as if someone prepared the surface to do just that. So let's go ahead and tackle that task.

First, I need to isolate the area on the terrain that fits my description. Luckily, I already know a slice of the terrain that fits that criteria. Create a height field mask by object node. This allows you to use geometry to create a mask. So bring in the partial terrain and connected to the second input.

Now we have a perfect mask where we did the split before. This is where the rail will be. So it should only happen in this slice, but not everywhere. This area in front is a good example where we would want to keep the mask, but on the mountains a bit farther in the back, we don't want to do any changes.

So how can we narrow down the mask selection? We can use a wrangle to make a distance check to the different elements that already exist in our project. The partial terrain is the basis for that check, which consists of polygons. So a primitive wrangle makes sense. In addition to the partial terrain, we also have the oriented curve.

This will allow us to check if we are way to high for towers and another option or the tunnel curves, they are part of the curve, but you will see that we can use them differently.

I connect the tunnel curve to the third input and the main curve into the second one. In case you are wondering the order in which you connect anything beyond the first input is not important. You just need to be aware of the connections when using the vex functions. Well, I have the tunnel curve already merged in.

I am going to do the polywire right here. Otherwise I would need another merge to bring in the tunnel geometry for later use. We have the thickness for the tunnel on our control node, and we should use it here as well. This will help to keep the project consistent. In case you want to try different settings.

This geometry will be used to project onto the height field later. So I want to make it slightly bigger than the real tunnels and divisions don't really matter yet, but that follows after the mask. Once again, if you look at it from this view, I want to remove the mask from deeper canyons, mountains and tunnel entrances.

I have two different objects connected. And for each of my current primitives, I want to get the distance to both that distance. For example, the curve of the second input is once again, distance with @P and min pos. And here you have to be aware of the connection. When you mix them up, you might get a completely different result, or you will wonder why your parameters do not work, as you intended. 

A reminder for minpos. It uses the position you provide. Here my current primitive and then searches for the closest position on the whole geometry coming through the input index you provided. Now that you could see these two lines on their own. I am repeating the minpos on the curve, but this time I am saving the returning position in a variable.

By the way, have you noticed how he learned his lesson and now uses @P even though he is on a primitive Wrangle? I am so proud. 

Anyway, this position, regardless of the distance is my first factor that might exclude it from the mask. If a primitive has a higher position than the closest rail point, I remove the primitive.

This primitive is at least on the same height as the rail. And it makes no sense to smooth that surface for towers to stand on. The one at the end is a toggle for the function to decide if the points belonging to this primitive should be deleted as well. Now to our two distances. I want to test both against a channel so that I can control the result with sliders.

If the condition is true, I remove the primitive as well. Well, I, the mask where the rail is farther away than my setting with the tunnel, I want to remove what is below my channel. I already initialized both channels and with a rail distance of 20 and a tunnel distance of 100, my mask almost vanished. So let's take a look at how this affects the mask.

If I increase the rail distance more and more of the mass comes back in the bigger, this value is. The farther away the mask is allowed to be at the same time, you can notice that we don't have any remaining mask above the rail with a distance of 30. I have the normal ground covered while it does not follow into the Canyon.

Now the 100 and the tunnel distance seems to go into the right direction. If I lower it, the mask comes back around the cliffs because obviously those areas are close enough to the rail. But it would not be ideal to create a smooth path there. It would not make much sense. So bringing that value up to about 50 gets rid of these areas altogether, but we do have some problematic scenarios left. Areas where only fragments poked through the threshold.

And when the rail moves in parallel and close to a cliff without creating a tunnel. To handle any cliffs like that and help with the fragments. We can filter out more terrain for that. Create a mask by feature note. This note allows us to specify parts of the terrain with certain aspects. And then we can decide what to do with that.

By default, it is set to use the slope of the terrain, which is what we need to handle the cliffs. Whatever mask is created by this node, I want to subtract from the existing mask, but we need to change this Ram. Everything that has a high slope angle should be selected, but only when it reaches a certain threshold to get a better look at the created mask, we can switch back to replace.

This will allow us to fine tune the ramp.

With this feature selection, we solve the cliffs without having any effect on the section we actually want to get. Now, let's jump over to the fragments. This situation got better as well. When a small piece of terrain pokes into the range, they probably also have a strong slope. Those sections now get filtered out the remaining parts in this example.

Are so small that we could get away with it, but let's say we have to clean this up a bit more and get rid of smaller pieces of the remaining mask. Here is a simple trick to do that. First, you create a mask blur this blurs out the existing mask, spreading this election, but also making it weaker when it was already a small area.

Then you directly follow it with a hight field remap node. This works like the fit function in vex. You take the incoming range and remap it into a different range. My target range is still zero to one, but I increase the incoming min value. That means anything not reaching this value is filtered out.

And with that, we have the mask done for the ground blur. I am placing an output. No, here, since I can use this mask later for a scattering example, now, of course this will not solve any possible terrain, but you should be able to come close when adjusting the distance check in the selected slope. Let's finally use the mask to blur out the ground for the towers.

This time using a height field blur, not the mask blur. By default, this blurs out the whole height layer with the mask layer grayed out. So connect the mask to the second input, which activates the mask layer. But when you now change the radius of the blur, it still affects the whole field.

You have to activate mask aware, blur for the mass to be used. Now only the masked area is blurred. We bring back more overall detail later. So this can be on a very high setting. Let's clear the mask once again. The smooth ground was one goal. I had the other one was to change the terrain around the tunnels.

It shouldn't look as if the tunnels are just sticking out of any terrain. Terrain and tunnel should blend together. How could we accomplish that first? We can take the tunnels and if we like we can change its position a bit, not an exercise, but in why this will create additional height. Let's give that three extra units as well.

And now we create a hight field project behind our latest terrain. Here we connect the tunnels into the second input. This will now embed the tunnel shape on top of the terrain we made this slightly bigger and higher, so it should cover all areas. This created a very blunt feature into the landscape and it doesn't really help to blend in the tunnels.

So after adding this feature in, we now try to hide it again to make it less obvious. And that means we need to find a good mask. Again, this time we have an even better starting point. We can create another mask by object node, and use the same shape we use to project onto the terrain. And this almost gives us what we need.

The whole projected surface that is clearly visible is also now masked, but we do have additional terrain in the mask that we do not want there. The area above the tunnels are also in the mask. The mask by object is set to project, which is why all that extra surface got caught. Now you can turn the tunnel into a volume and change the method on this node to use a fog volume that would do the trick.

But for argument's sake, let's say we had to use the project, or we already had this mask and now we need to find a way to get rid of it again. Then we would need to create a workaround. The main issue is the height. If we can limit the height, we should be good. So throw down a mask by feature, turn off the slope and activate mask by height, hit compute range.

And by default, this basically selects everything. But if we would set the max height value to where the tunnels are, this could be it. We can get that information with an expression. But before, let me rename this node to make it clear what we are doing next. This transform is now the tunnel push node. We go back to the max height parameter, and we type B box, the path to the target node and the constant name for the Y value of that target node.

You can find the available constant names in the documentation. And as you can see that limits the masks reach. Now, all we have to do is combine the previous mask with this new one, by using the height field layer node. The layer we want to combine is the mask layer. And we don't want to use the replace mode.

We need either the minimum or multiply mode, both will work and only keep mask values where we have any values on both masks. This whole process was non-destructive as it is Houdini's nature. So we can still go back to the tunnel shape and make it bigger or push it even higher above the terrain. The resulting mask will always adapt to these changes.

You can see that the mask is not fully saturated since I left the mask by feature on its default ramp, that leaves out the end of the range. That might not even be a bad thing, but we should remap the mask this time to get more of it back for this. We lower the input. Max value. With that even a weak mask is enough.

And we have a solid selection of the added terrain surface with this mask. We can do additional work, but that's a topic for the next clip.

Leave a Reply

Your email address will not be published. Required fields are marked *

David Kahl VFX

a Software Developer, Nerd and VFX Artist based in Germany
Visit Patreon
linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram