Jump to content

- - - - -

Procedural Mountains and Slacking Off

Goblinson Crusoe rpg isometric turn based lazy slacker
4: Adsense

ApochPiQ's Dude, Just Chill Out entry made me feel bad and dirty. I've been neglecting GC lately, and I've been neglecting this blog as well.

Since the last time I updated about GC, I have gotten quite a bit done. However, so much of it has just been bookkeeping, general clean-up, some refactoring, and so forth. I fixed some bugs in the general framework, tidied up some use cases, etc... For now, I haven't done anything further with the YAML-based variant of the framework, and am continuing to work in Lua. I just... I like Lua. It feels right to me, after so many years of working with it. C++ just feels so cold and unyielding, and I don't really like working with it much anymore, except for those times that I have to.

I've got a sort of TODO list of things I want to blog about (it's pretty long), and hopefully I'll get to them in the near future. Time. Man, there just isn't enough of it. With one kid at 10 months and another one on the way, set to arrive in July, plus work and wife and winter, there just isn't any time.

Anyway, in order that this update not be empty and completely useless, I'll just talk about mountains. I've started out writing numerous posts about procedural generation and how it has benefitted me in building GC, but each time the post starts to balloon into this gigantic thing. Procedural generation is awesome, but it's a big topic as well. So I'll just talk about mountains instead.

Cellular noise. I'm sure that almost everyone has heard of it or seen it. It's an old stand-by in the procedural world. In some places, it might be called Worley noise or Voronoi noise. Cellular noise is built by seeding the coordinate space with a scattering of randomized points, then for each location in the space you determine the nearest seed point. Variants of cellular noise might assign a certain value to all points that "belong" to a given seed point, or might calculate the distance to the nearest seed point, or the distance to the nearest N seed points, and use these values in various forms.

Of particular interest to me in mountain-making is the variant of cellular noise that is often labeled as F2-F1. In this case, F1 and F2 are the distances to the nearest and second nearest seed points. By subtracting the first nearest distance from the second nearest distance, you end up with a rather remarkable pattern:

Posted Image

Looks like mountains to me. A little too smooth, perhaps, a bit too crystalline, but that is easily remedied with just a little bit of fractal fBm distortion applied in the X and Y axes:

Posted Image

There we go. However, that is mountains (plural) and I basically want just mountain (singular). Or, at least, I need an isolated chunk of mountain, and not the whole mountain range. So I bring in my old amigo, FuzzyDisk. FuzzyDisk is a cross section of a sphere in which values start at 1 at the center and fade out to 0 at radius. I can bias the output of fuzzy disk a little bit to tighten up the transition, and obtain a mask that looks something like this:

Posted Image

A simple multiplication operation later, and I have isolated my mountain piece:

Posted Image

Now the fun begins. I have set up in my project's workspace folder a .blend file for Blender. It includes the standard Goblinson Crusoe light setup, and some tri-planar materials for various rocks, dirts, cliffs, etc... One of these materials looks something like this:

Posted Image

Looks a little ugly, but essentially what it does is this:

1) Tri-planar map a stone material to the bulk of the mountain.
2) Mix the stone material with a white snow material based on
a) Elevation
b) dot-product of the surface normal with the vertical axis
3) Mix the stone/snow mix with a greenish material at the base of the mountain, again based on a) and b) above
4) Mix between the final color and black based on elevation to "snip" out the lowest portions of the mesh, isolating the mountain pieces
5) Mix between white and black using the same elevation factor as (4), and use the result as the alpha channel.

This material is applied to the mesh, which is constructed by subdividing a plane and applying the mountain heightmap as a displacement modifier, and tweaking the scale of the displacement to suit:

Posted Image

Then, the thing is rendered. The result will be a mountain sprite that can be imported into GC. The sprite is anti-aliased, and smoothly blended at the base to blend well with the ground terrain. Here is a mountain sprite:

Posted Image

I'll do a bunch of variants, pack them into a material and import them into the game. Here is what they look like in game:

Posted Image

Simple as pie. The process isn't fully automated (I do still have to import the heightmap into Blender and hit render) but it is very fast. I can generate numerous variants by re-seeding the cellular generator, and by tweaking the material and textures I can create variants for different types of mountains. It's quick and easy, and it certainly results in better mountains than I would ever be able (or willing) to create by hand like a real artist would.

There. Now I don't feel bad for having posted another worthless post. This was only partially worthless. Conscience soothed, back to slacking off.

Jan 28 2013 08:25 AM

I love your posts. Looking good and love the screenshots to show what you are doing.

Jan 28 2013 11:27 AM

Yes very cool stuff, keep it coming even if it seems easy, may not be for others! :)

Jan 28 2013 11:06 PM

Thanks, guys.

Jan 30 2013 07:11 PM

Nice stuff :D


( It's almost enough to make me want to work on my own stuff at the weekends.... almost... *looks at DmC*.. but not quite ;) )

Feb 03 2013 10:41 AM

These mountains look really nice. They remind me of the Civ mountains.

Apr 14 2016 07:27 AM

Awesome mountains! Can you show more of the pack?

Note: GameDev.net moderates comments.