- You can download the Unreal and Houdini Assets here. Here’s an Installation video.
- For a major part of the project I followed tutorials by Ben Schrijvers and Andreas Glad.
- Don’t be afraid of Nodes and Scripts. It’s not as hard as it may look.
- For the water I used a normal-map from the Unreal Starter content.
Could you introduce yourself to us? Where do you come from, what do you do, what projects have you worked on?
I’m Simon and I started programming with QBasic and Pascal when I was young (here are examples), realized that coding is hard, change to 3D art but always kept my interest for the technical side of making game which now culminates in being a VFX artist – a profession which combines art and tech very well.
Professionally I worked as 3D Artist on Sacred 2 and X:Rebirth and as VFX Artist on RiME, The Invisible Hours and now on WiLD.
Private game dev related projects are my Game Art Trick Blog, a German Game Dev Podcast and my Youtube channels for Unreal and Houdini tutorials.
How did you start working with Houdini in the first place?
Houdini and me got friends during the work on The Invisible Hours where I needed to make a small liquid simulation which could paused, reversed and played forward in realtime (because in the game you can stop, reverse and forward time). This was the result:
I had no idea how to bring a liquid simulation into Unreal but luckily an amazing tech called “Vertex-Count-Agnostic Morph Target-Based Fluid Animation” was just implemented into Houdini and so I was able to get my fluid simulation into the game. The technology was originally developed by Norman Schaar.
If you want to know more about the implementation, you can watch this section of my talk “Cool Stuff with Textures”.
Could you talk about the main task of your project? What do you want to achieve here? What are you trying to build?
I wanted to learn how to make a procedural generated river for the Realtime VFX River Challenge but had no idea how to start. Accidentally I stumbled across this amazing tutorial from Ben Schrijvers where he talks about the rivers in Horizon Zero Dawn. I was hooked and had to try it out!
By the way, there is another really cool Houdini river tutorial by Andreas Glad:
These videos where my main foundation and helped a ton to get everything started.
Ok, let’s talk a but about the main thing that allows us to craft these big procedural places. First of all, how did you build the lanscape? Is it generated from the Lndscape tool in Houdini? How did you craft it?
The terrain was super-complex. Let me illustrate the creation-process with a video to make sure everyone can follow along:
Source: Terrain Creation in Houdini
Just kidding. The shelf-tools make it very easy to create a terrain. I just set a smaller size and it was ready to go.
What is the way you’re building the river itself? There’s a big spline that sort of guides the river? How is it actually set up? What are the things you can do here with it?
The first steps are 100% copied from Bens tutorial and they are fascinating. First, you create a spline and let it “fall down” on the terrain. This is done by reading the height of the terrain at the spline-point-positions and then moving the points to this height:
Adapting a spline to a terrain
Next, you let the spline-points “roll” down the hill to integrate the river a bit better to the terrain:
Rolling the spline-points down the hill
Actually, they do not roll in a physical way. Instead, you use the underlying surface-normal and the normal of the point to calculate a local axis for each point (which points away from the spline and down the hill). Then, you move the points along the calculated axis a little bit (this process is documented very well in Ben’s video).
The next step is to make sure, that the river does not flow upstream in case the terrain directs it to (because there’s a little hill where the river goes along).
A little Python script makes sure that a spline-point is never higher in 3D space than the point before on the spline:
Avoid river from flowing upstream with Ben’s little Python Script
Another nice trick for a more natural appearance is to avoid continuous slopes but instead let the river flow in steps (for better visualization I show the river-geometry here, but actually we’re still only working with a single spline for now).
Transform continuous slopes into steps.
Finally we reach a step where I contribute my own ideas: I add colors to the spline to mark where a slope is (green), where it starts (turquoise) and where it ends (red). This will help me later to blend different water-textures and place particle systems.
Let’s go a little bit faster over the river-geometry-creation since all of that is perfectly fine explained in Ben’s video. The most important point is, that only the outer edges of the river get aligned again with the terrain (like we did with the spline in the first place):
Build river geometry out of the spline.
How did you manage to achieve the deformation of the landscape where the river flows? This looks really interesting! What is the way this deformations take place?
Again, it’s 100% Ben’s workflow but it starts by moving the terrain below the river geometry so that it does not intersect in any way:
Move terrain lower than the river geometry.
Then, for every point in the terrain, you shoot a ray upward. If it hits the river geometry, this point will be moved upward to the hit-position:
Show rays upward and if you hit the river, move the terrain to this height.
Every point which didn’t hit anything, gets its original height assigned again:
Every point not hitting anything gets its original position assigned.
Here you can see how everything behaves now, when you change your spline:
Procedural Terrain Deformation.
Then the terrain height-field gets converted into polygons and re-meshed. Now it’s ready for being used in Unreal:
Convert height field into polygons and optimize it.
Even if it’s not part of the question, I would like to add some details about UVs, Materials, Flow-Maps etc.:
The river geometry you saw before was just used to carve the terrain. The actual river is a bit thinner, got UVs and was subdivided (note, that my slope-colors are still there):
Talking about UVs: Since the spline always varies in length, the UVs must adapt to that. Luckily this is very easy in Houdini. First you create your UVs in the 0-1-UV-Space and then you measure the spline-length. This value can be used to scale the UVs. Here you see me changing the spline and in the lower part you see how the UVs auto-adapt. Believe me, if you experienced this once, you never want to manually create UVs anymore :D
Automatically adapting UVs.
Another detail: I wanted to make the river bed darker and wet. To do that, I shoot some rays from every terrain-polygon upward and if I hit the river, I assign a color to all points of that polygon. The created mask looks like this:
And here is an example how much difference it makes when using the mask in a material to assign different diffuse and roughness values:
River bed with different diffuse and roughness values.
Generating the flow-map for the river is super easy with Houdini. You just tell a special node “This is my river geometry and this is the spline which indicates the river-direction” and boom, your river geometry suddenly has vertex colors assigned representing the flow of the river:
Another node can be added which makes the flow-map react to obstacles. Now the water can flow around them:
Flow-Map Generation with obstacles.
And the best: You can trigger the baking of the flow-map in Unreal! No need to switch back and forth between Unreal and Houdini. Just expose the Houdini-“Render”-Button as Parameter. Here you see me changing the obstacles and then render a new flow-map (note: the baking takes a longer time than in the video):
Flow-Map Baking in Unreal.
To get some foam on the water around obstacles, I use a so called “isoOffset”-node. It stores basically the distance to an object into the vertex color of the river. Then I spice it up with a little noise and the mask is good to go:
To make the foam-mask less static, I use a simple Photoshop cloud pattern which I move along the river and subtract it from the original mask. This adds a more interesting feel:
Adding more motion to the foam mask.
And since we’re talking about foam: The cascades get a simple foam texture too, which is only shown at the slope of the river (I masked this slope at the beginning with vertex colors when I was creating the spline). The foam structure is scrolling faster than the river water:
Using a mask to blend between water and cascade.
Because I stored where top and bottom of my cascade are, I can now filter those elements (these lines where used to generate the river-geometry), create a point in their center and copy a dummy-cube to this point which will exchanged against a particle system in Unreal later:
Particle Placement at cascades.
For the particles around the obstacles, I’m using a nice node called “Intersection Analysis” to get the intersection of obstacles and river. Those intersection-edges have points. To a random number of those I copy a dummy-box again (which is exchanged against an particle system in Unreal later):
Particle Placement at obstacles.
Here you see how it looks when I exchange the dummies in Unreal:
Exchanging Houdini-Dummies with Particle Systems.
How are you going to prepare and export this project into Unreal? This seems like an excellent way of doing it?
The so called Houdini Engine is a plugin for Unity, Unreal, 3Ds Max, Maya and Cinema 4D and executes the node networks you create in Houdini directly in the mentioned programs. So what I have to do, to make the terrain and river show up is to save my Houdini-File as Digital Asset. This can be imported and used like any other asset in Unreal:
Using a Houdini Digital Asset in Unreal.
Now, I can change parameters (which I exposed in Houdini) or change the spline to make the river take a different road:
Different rivers by just changing the spline.
The materials are still created and assigned in Unreal but you can pre-assign materials (you can find my tutorial about this here).
Of course, it’s not perfect yet. Further improvements would for example be: avoid placing obstacle-particles “behind” objects (away from river flow direction), setting the orientation of the obstacle-particles along the flow-map so that particles move into the direction of the flow, accept Unreal-Terrain as Input, improve performance of the node-network so that changes on the spline get calculated faster, narrowing/extending the river-width depending on the area (like in Ben’s video), …
Overall, how difficult is setting up this type of asset and using it in games? I believe ti might prove most useful for developers, but many might be taken aback by the complexity of the whole thing.
Yes, Houdini has a steep learning curve. And since the game dev tools are brand-new, sometimes you will find bugs, anomalies in the documentation or you’ll struggle to get the output as you want it to be.
But that’s a common situation for game developers, isn’t it? We’re often working with cutting-edge technology which has to be tamed first. Most importantly: you’re not alone. The Thinking Procedural Discord is full of very nice people which are eager to learn and help. You can even find Sidefx developers in those chats!
I can totally recommend checking out the software. Every day new amazing tutorials appear and the game dev tools are a great way to use the software not “just” for baking out some simulations into flip books but improving the workflow in a way, that classic workflows feel like stone-age.
Thanks to Damien, lKruel, mgw, Ambrosiussen, Glad and Julián (all from “Thinking Procedural” Discord! Wouldn’t have been possible to finish the project without you.
- You can download the Unreal and Houdini Assets here. Here is an Installation video.
- Discord: Houdini “Thinking Procedural”
- Houdini river Tutorial by Ben Schrijvers
- Houdini river tutorial by Andreas Glad
- Simon’s River Challenge Thread with more details
- Simon’s Talk containing the Liquid Implementation in “The Invisible Hours”
- Simon’s Unreal and Houdini Youtube channel
- Vertex-count-agnostic Morph Targets by Norman Schaar