Today's lesson is cliffs. I've done a little bit about cliffs before, but there are a few new things I'm doing. If you are of the school of thought that isometric graphics for traditional 2d iso games should be hand drawn, or that using a 3D modeller to create such graphics is cheating, then this might not be for you. I, for one, would be hard-pressed to hand draw a decent looking cliff; most likely, it would end up a smeary blob of color.
My Accidental Engine can implement isometric maps with heightfields mapped with repeating ground terrain textures, and at it's foundation it is really a 3D engine that looks isometric, enabling me to do some things easier. Thus, this entry sort of assumes an engine with similar capabilities (notably, allowing the ground to be a heightfield with varying elevation).
All of my levels are usually randomly generated, so I also need to take that into account when I create artwork. Things such as cliffs will need to come as sets of cliff pieces that can be puzzled together in any combination; edges need to align, geometry needs to be consistent, and color maps need to tile.
The first thing we need to do is construct the geometry. I don't want to go into too much detail here, as the process really isn't all that difficult. The main thing you need to ensure is that the left and right edges align, so that multiple instances of the cliff piece can be set down adjacent to one another and the geometry edges will match up. The following image is a wireframe rendering of a sample cliff mesh. I began with a plane, subdivided it several times then UV mapped the entire thing to fit a texture. Afterward, I folded the top section back and the bottom section forward; these are the edges that should align with the ground terrain above and below the cliff; the top fringe will rest on the higher ground, and the bottom fringe will rest on the lower ground. I used proportional editing to create bulges and cavities in the cliff face, and just sort of rough it out. We don't really need to go too deeply into detail here, since we're going to get the bulk of our surface detail from the texture map; we just need a basic shape to give it a sense of form.
Note that the left and right edges have the same profile, so that the mesh can tile with itself.
Now we need to create the texture to give it some detail. The texture needs to take 2 things into consideration--the type of stone forming the fliff face, and the terrain texture with which it needs to blend. Creating the terrain textures is a subject I have covered elsewhere. For the purposes of our example, we are going to use the following ground texture:
It's not much, but it will work for our purposes.
Next, we need the texture for the stone of the cliff face. Now, a few things must be taken into consideration when deciding what to use for this. Color and texture of the native bedrock, fracture patterns, how the colors will contrast with the colors of the terrain, etc... For this I can only suggest you take a look at real cliffs and rock faces, and see how they compare with the terrain, with the local soil, etc... It's pretty easy to get this wrong and have cliffs that jar and do not fit.
To begin the process, you need to select a rock texture that fits your needs. One of the most important things I can say about the texture you select is that it not have large, coarse areas of shadowed detail. You want a nice, even color map with lots of very high frequency detail, but you don't want low frequency detail, as it will interfere with the process. I will often take my digital camera with me when I hike, and if I see a large, fairly smooth expanse of stone, I will take a high res photograph of it. If there are large, obvious faults, fractures, cavities or bulges which affect the lighting, it is not so useful since I will need to do a lot of hand editing to remove the features. For this reason, some good starting bases are photographs taken of asphalt, cement, etc... Flat expanses with a grainy, stony texture that lack shadowing artifacts. Here is a good example, and the texture map we are going to start with. It's from a photograph of weathered asphalt. I snipped out a square, then applied the Gimp's Make Seamless filter to ensure that it tiles. (Here is where large, low-frequency artifacts can fail; the Make Seamless filter is a simple blending filter, so obvious faults will be strangely handled and look bad.)
Fairly nondescript, and if we apply it as-is to our cliff, it's not going to look all that great:
Since we use a stone texture with no low-frequency detail, we are lacking in surface roughness and our cliff is too smooth. Some cliffs might appear somewhat smooth due to wind erosion, but this is just a little too smooth. What we need to do is take our seamless texture and add some low frequency detail. However, we need to do it in a manner that ensures our texture remain tileable.
The way we are going to do it is we will create a bump map from a perlin noise module, and use that bump map to modify the color map of our stone texture. At each point in the bump map, we calculate the normal of that point based on adjacent points, and perform a dot-product lighting calculation to generate an intensity map that is multiplied by the color map to get the final surface texture. The following sequence of images shows a seamless Perlin noise bump map, the intensity map generated from it, and the final modified stone texture map with the surface roughness added.
I have a toolkit of various functions that allows me to quickly and easily manipulate Perlin noise generates and buffers of data. With such a toolkit I can easily experiment with different settings to modify the character of the final texture; I can increase the roughness, use different basis functions to change the character of the roughness, change the mapping to stretch roughness features in a given direction (useful for simulating strata of sedimentary layers) and so forth. The previous images used 6 octaves of FBM ('standard' octaved Perlin noise) using Perlin's simplex noise for the basis function, and quintic interpolation.
That gives us a nice stone texture to work with. Now we just need to fix up the top and bottom edges so that the cliff will blend nicely with the ground terrain. This means adding an alpha channel to the image so that it fades out at the top and bottom. Blender was being a bonehead for me this morning (actually, I'm the bonehead) and I couldn't figure out how to blend in the mockup, so I went ahead and created a pre-blended version of the texture with a fringe of our dirt at the top and bottom. In the Accidental engine, I can simply blend the cliff geometry on top of the terrain, and the blending is nice and smooth, but for the purposes of this discussion, we'll use the following final texture map for our cliff segment:
That looks pretty good, let's go ahead and put it on our cliff geometry and see how it looks there:
Looks good so far, now let's put it on some terrain and tile it to see just how it might look in-game:
That looks pretty good, I'd say. There are some stretching issues (which could be tackled in the geometry construction phase), a few visible seams (I screwed up editing the mesh, and didn't feel like starting over), and the top and bottom fringes look a little wonky (they look better in-game, when real blending is done, since the rock texture blends directly with the terrain) but all in all I'd say that's not bad for programmer art.