Skip to content

67. 3D – Terrain! (hills)

May 27, 2013

What I’m showing you just gets cooler and cooler (at least I think so). This time it’s how to make hilly terrain, put stuff on it, and then walk about on it. You can guess that’s not easy, and that’s the main downside of the best 3D stuff. But if you’ve kept up with me so far, you’ll be fine – and terrain really adds to the realism.

First, I’m not going to include as much code as usual, because this post is more about explaining the approach to solving quite difficult problems, and because the code is quite a few lines, and I didn’t want to clutter this post up too much. The code should be fairly straightforward to understand, if you are interested in doing so.

The problems with terrain

So far, we’ve worked with a flat surface, which makes things fairly easy. At least we always know what our y value is!

If we want to add bumpy terrain, we have to solve some problems

  • how to create a map that looks natural and isn’t too up and down
  • how to make the terrain run smoothly into the surface around it
  • how to create a mesh and texture for it
  • how to put things on the terrain, such as trees
  • how to walk about on top of (not through) the terrain


Sampling and interpolating

You will most likely decide a few things fairly quickly. One of them is that you can’t set every pixel by hand, and that you should just set every nth pixel (sometimes known as sampling) and interpolate the others, where n is a number such as 48, and n should divide evenly into the height and width.

Merging with the surface around

Another is that at its edge, the terrain should be at the same height as the rest of the map, so there isn’t a gap, and (unless you specifically want it) there shouldn’t be cliffs at the edge of the terrain. This means you have to find a way to make the terrain quite smooth at the edges, even if it is bumpy in the middle.

A solution

I dealt with both these issues, and the question of how to design a terrain map, by using the noise function built into Codea. The noise function works by dividing an area into squares and creating a value for each of them that depends on its neighbors, so it isn’t completely random. You can also set how bumpy the results are.

So what I did was this. Assume I want terrain with width=w, depth=d, and I’m going to calculate the height every p pixels.

Then assuming I set a start and an end pixel, I need a table with (w/p+1) columns and (d/p+1) rows.

I calculate noise values for all these points – but this would result in cliffs and gaps at the edge, if I didn’t adjust them. So what I do is phase the noise in. At the edge of my terrain, I set the height equal to the height of the surface beyond, so it meets exactly. As I move into my terrain, I prorate between that surface value and the noise value, eventually just using the noise value. How fast I do that is up to me, but it ensures that the terrain rises fairly evenly.

What do I mean by using the noise value? Well, this is a value between -1 and +1. What can I do with that? I ask the user to give me the minimum and maximum y value for the terrain, then I calculate the minimum and maximum noise value, and pro rate accordingly. So if the noise value for a point is 1/3 of the way between the minimum and maximum noise value, then the height will be 1/3 of the way between the minimum and maximum y value set by the user.

Creating a mesh

So now I have a set of height values for every p pixels in my terrain. I need to create a mesh and texture it. This isn’t too hard, since you can make squares out of every four points, and triangles from those squares.

Adding objects to the terrain

To add objects like trees to the terrain, we need to be able to calculate the height at any point, not just at every nth point. I found the most common way to interpolate between four corner points is called bilinear interpolation, and it works pretty well.

Walking around on the terrain

This is the same problem as adding stuff, because we need the height at a given x,z position, so we can write a function that does both. There is one little problem, that when you are walking uphill, you are staring straight into the hill, and when you walk downhill, you’re staring straight into space and can’t see anything below in front of you. I modified LookY (which tells the camera where to look) in draw so it is based on the angle you are walking at, but you might want to see if you can improve on this.

Making it versatile

When I first wrote this, I required that the whole map be divided into squares of the same size, and terrain could only be placed in those squares. But suppose I want to start the terrain 10 pixels to the left, or I want a smaller square size for a second terrain area?

So I’ve created a table of terrain areas, which contains their start and end x,z values, as well as their table of heights. Then, when I am adding trees or just walking around, I can test if my x,z is inside a terrain area, and if it is, I can look up its table and interpolate the height. This means I can put terrain anywhere I like, and have completely different terrain areas if I want.

The final option is that you instead of relying on noise to set the heights, you can specify your own table of heights, ie you set a value for every nth point.

All of this is demonstrated in the code here, which I hope is commented enough for you to follow it.


From → 3D

  1. Dreamdancer permalink

    In this code is also the tiling shader missing.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: