As someone with a good eye for art/composition, no real artistic talent to speak of, and fairly enormous world datasets: I have absolutely zero interest in hand-painting my terrains. Furthermore, I just don’t like the idea of a height map being “locked-in” to a given set of painted layers or manually-adjusted height information. Beyond that, I just like procedurally-generated content — it’s how I’m able to make a game like Sacrilege by myself. I have faith in the procedures, and the procedures… Well, have absolutely zero faith in me, but I force them to do their jobs anyway.
The Height Map
Really, the most complex and time-consuming part of your terrain workflow is (or should be) the creation of a solid height map. It’s fairly easy to generate a height map in Photoshop but… Don’t. It’s not. It’s just… It’s weird.
What you really want to do, if you’re looking at generating a variety of terrain for your game, is invest in terrain generation software like Terragen (which I hate), Vue (which confuses me), or World Machine (which is great).
World Machine is just magic. It’s somewhat impracise magic, but if you’re okay with that, it’s simply magic. We used it on Starhawk to form the basis of most of our maps for the campaign and for multiplayer, and I can still hear Andrew Weldon cursing the software in the back of my head. I relied on it heavily for work with Voxelfarm, which hopefully I’ll be able to use again soon given the unveil of their forthcoming Unreal Engine 4 plugin (maybe? hopefully? these people are like Fort Knox with their information and timelines). Anyway, let’s continue thinking World Machine is magic. It:
- Has a node-based interface; so familiarity with how to get the most out of UE4 node networks will put you flat at home with World Machine dataset manipulation.
- Has the ability to generate a grayscale mask for several different layers of terrain; we’re talking, flow masks, deposition masks, wear masks, snow masks, coast masks, water masks, and even more masks than that. This isn’t super useful if you’re looking to build a complex procedural terrain material in UE4, but it’s incredibly helpful if you’re working with Voxelfarm.
- Has the capability of generating absolutely enormous datasets. Granted, I believe UE4 only supports height maps up to 4033(ish) pixels wide and tall, but you never know when you’ll need a ginormous dataset.
- Is also, compared to a lot of the alternatives, relatively cheap. It comes in a free flavor, a priced flavor, and a professional flavor (which you should absolutely get if you’re serious about this kind of stuff; it makes data generation times so much more friendly).
- Oh, and if you go the World Machine route: get Geoglyph. Don’t even think twice about it, just do it. It even has a free version!
Oh, so you got World Machine, learned how to use it, and generated your first height map already? Well, now we’re on the same page. Here’s a little corner of my terrain:
A bare-bones landscape.
That’s my blank terrain right thar. There. Thar.
And this is the material that will eventually be applied to it:
The material we’ll be applying to the terrain.
So, you’ll notice that it’s actually not that complex. I mean, as far as PBR materials go, this is practically a walk in the park. I didn’t take nearly enough screen shots while working on this, so we’ll just go over what I wasn’t dumb enough to forget.
First off, this is terrain, which basically means it’s a uniform grid of points on the XY plane with height applied on the Z axis. That’s it. There are no caves, there are no overhangs, there’s just the grid and the height. That’s what you get for using a 2D height map: none of the cool stuff you’d get with, say, a voxel terrain. WHICH I’D LOVE TO BE USING RIGHT NOW. Wink wink, nudge nudge Voxelfarm.
Anyway. Since we’re dealing with a grid, straight-up UV mapping the landscape would result in a very noticeable, grid-like UV mapping. So, the first course of action is to apply some relative UV tiling to give the terrain texturing a bit less obvious of a texturing pattern. We do this by basing the UV coordinates on the point’s absolute world position (which would be weird if the landscape wasn’t static, but it is, so we can) and dividing it by the relative tiling size we want from the textures. This is going to, basically, serve as your “master UV tiling” parameter, though I also set up explicit ground/cliff multipliers just for good measure to make sure each layer looked as good as it could. That bit of the node network is right here:
Relative UV tiling material node network.
And that leaves us with our terrain looking like this:
Base (untweaked) material applied to landscape.
So, yeah, the tiling isn’t based on the grid, which: hooray! It is, however, very obviously and noticeably tiling the applied textures. Luckily you and I are smarter than the machine, and we can expose any parameter in the node network to a material instance where we can tweak parameters and, if they’re simple things like tiling scale or what-not, avoid a complete shader recompile. Here’s a sneak peek into some of what I exposed:
UV tiling/scaling parameters exposed via material.
And that yields:
Yay, somewhat better.
Now, this next bit I can’t go into terribly much except to say that I think things like the Unity Asset Store and the Unreal Marketplace are actually gold mines that should be exploited as much as possible by indie developers. Sure, things cost money, but they’re things you can use! And, more importantly, they’re things you can learn from. The snow texture I’m using in this level is all sorts of fancy, with subsurface scattering, a colorized fresnel effect, gloss map (ie, one minus roughness), blended top and bottom textures to give the appearance of snow covering some kind of surface below. This material function and its dizzying array of options comes from C-Media Advanced Materials Ed. 2.
More exposed tweaking parameters that I can’t show you the node network of because it’s from someone else’s material package.
One thing worth noting is that I have two materials that cover the exact same “layer” (land coverage). In this case, it’s two different types of snow, but in an outdoor landscape it might be grass/dead grass or, more commonly in my experience, grass/dirt. These two materials are blended together with a simple linear interpolation with an interpolator defined by a noise function. There are no “right” parameters or ways to set this particular feature up; I’ve used the Noise node, I’ve used pre-defined textures, and I’ve used all sorts of parameters to customize that. At the end of the day, what’s going to look good is going to be a combination of parameters/techniques that you experiment with yourself and find to be a good fit for your environment.
So between mucking about with the snow parameters, tiling, cliff hardness/slope parameters, and everything else I have exposed via the material instance, I end up here:
All things considered, this is actually a fairly simple procedural texturing material. Just blending three separate material functions together: cliff, snow 1, and snow 2. I tossed some dead/winter trees and ice chunks into the mix and ended up with my finalized first-pass of the snow environment:
~ fin ~