# Terrain Algorithm

Document Sample

```					                                Terrain Tutorial

The Fault Algorithm

This algorithm is a very simple one, yet its results, although not the best, are pretty good. The
technique is not limited to planar height fields, being also applicable to spheres to generate
artificial planets. Paul Bourke and Hugo Elias have posted tutorials on the application of this
algorithm to spheres.
To start with we'll have a planar height field, where all points have zero height. Then we select a
random line which divides the terrain in two parts (in general these parts will be different in
size). The points to one side of the line will have their height displaced upwards, whereas the
points on the other side will have their heights displaced downwards. The following image
illustrates the first iteration of the technique.

The red points will have their height decreased, whereas the blue points will have their height
increased. So now we have a terrain with two distinct heights. If we keep dividing the terrain like
this then we'll get something that has valleys, mountains and so on (or at least we can imagine
them!).
The following images show how the terrain height map evolves as the number of iterations
increases.
1 iteration 2 iterations 3 iterations 4 iterations

8 iterations 16 iterations 100 iterations 400 iterations
OK, now lets look at the terrain itself after the same number of iterations.
1 iteration                                         2 iterations

3 iterations                                      4 iterations

8 iterations                                      16 iterations
100 iterations   400 iterations
Terrain Tutorial

Implementation Details

In this section we'll see how to implement the algorithm presented in the previous section. We'll
see how to compute the line that divides the terrain, and how to compute the displacement for
each iteration.
Finding a Line Which Divides the Terrain to displace the heights
The first problem is how to create a random line which divides the terrain. A first approach could
be to find a line crossing the origin with a random inclination. However this approach creates a
terrain which is anti-symmetrical, i.e. if we have a mountain in one place, we'll have a depression
on the other side. Therefore, to avoid this trap the line should not cross the origin in the general
case.
The line formula is

ax + bz = c

where    a*a + b*b = 1 and c >= 0

The formula above is know as the Normal Form. A simple way of obeying the restriction above
is to consider

a = sin(v)
b = cos(v)

where v is a random value.

Therefore a line, in its Normal Form, is an equation of two variables: v and c. So how do we
compute the pair v,c so that the line actually divides the terrain?
Assuming that we're using the Normal Form, the distance from a point (x1,z1), to a line, ax+by-
c=0, is defined by:

dist = a*x1 + b*z1 - c
The distance will be negative for all points on one side of the line, zero for points in the line, and
positive for points on the other side of the line.
Assuming that the terrain is centered on the origin the distance from the line to the origin, i.e. the
point is (0,0), is defined solely by c.

dist = a*0 + b*0 - c = -c

Therefore we only have to select a value for c which is smaller than the distance from the
furthest point in the terrain to the origin. Assuming that the terrain has a width w, and a length l,
then c should be defined in the interval [ -d/2, d/2 ], where d is defined as the square root of the
sum of the squares of both w and l.

d = sqrt(w*w + l*l)

The following code resumes what was explained above:

v = rand();
a = sin(v);
b = cos(v);
d = sqrt(w*w + l*l);
// rand() / RAND_MAX gives a random number between 0 and 1.
// therefore c will be a random number between -d/2 and d/2
c = (rand() / RAND_MAX) * d - d/2;

Then, we iterate for each terrain point and displace its height, or y coordinate, by a certain
amount. Points on one side of the line will have their height increased, whereas points on the
other side will have their height decreased. The following pseudo code illustrates this iterative
process

for each point (tx,tz) in the terrain do {
if (a*tx + b*tz - c > 0)
height(tx,tz) += displacement;
else
height(tx,tz) -= displacement;
}
Another approach to find a line which divides the terrain, is when the line is constructed by
selecting two random points from within the terrain. Assuming two points are given (x1,z1) and
(x2,z2), the line equation is

ax + bz + c = 0

where

a = (z2 - z1)
b = -(x2 - x1)
c = - x1*(z2-z1) + z1*(x2-x1)

The height displacement for each terrain point is computed as before.
Yet another approach to this problem is proposed on the excellent book "Game Programming
Gems". The two random terrain points, (x1,z1) and (x2,z2) are used to build a vector v1 where

v1 = (x2-x1, z2-z1)

Then for each terrain point (tx,tz), another vector vt is computed where

vt = (tx-x1,tz-z1)

Afterwards the y component of the cross product is computed and its signal will provide the
direction of the displacement. The following pseudo code illustrates this approach.

for each point (tx,tz) in the terrain do {
if ((x2 - x1) * (tz - z1) - (z2 - z1) * (tx1 - x1)) > 0
height(tx,tz) += displacement;
else
height(tx,tz) -= displacement;
}

The Displacement Factor
Another issue of this algorithm, is by how much we should displace the terrain heights at each
iteration. The simplest solution is to consider the displacement a constant at every iteration.
Another approach is to decrease the height displacement at each iteration without letting it reach
zero. We could drop linearly the displacement factor from iteration 1 to iteration n, and then just
keep it constant for iterations greater than n. For instance, to decrease the height displacement
linearly as the number of iterations increases we could write in pseudo code:

if ( i < n )
dispi = disp0 + (iterationsDone / n) ( dispn - disp0)
else
dispi = dispn
where

disp0 is the initial displacement
dispi is the displacement for iteration i
dispn is the displacement for iteration n

Special care must be taken when choosing the value n, as well as dispn. If dispn is much smaller
than disp0 then the value of n should be sufficiently large, otherwise the displacement factor will
decay too fast and the initial iterations will leave significant marks on the terrain. In this case if n
is not large enough then the faults created by the first iterations will be visible regardeless of how
many iterations we run.
Terrain Tutorial

Two Possible Variations

In the previous sections we considered that points on one side of the line would have their
heights increased, whereas the other points would have their heights decreased by a constant
amount. This is equivalent to applying a step function based on the distance from the point to the
line.

By swapping the step function it is possible to obtain interesting landscapes. For instance we
could use a sine function as the figure bellow:

In this case the surface will look smoother than with the step function. The next figure shows a
single iteration using the sine function:
Another interesting replacement for the step function is a cosine function as the one in the figure
bellow:

A single iteration with this function will look like:
The following figures show results obtained after 1000 iterations with all three functions.
Step function

Cosine function
Sine function
Use up your imagination to come up with other functions and let me know if you get interesting
results.
Terrain Tutorial

The Circles Algorithm

This algorithm is similar to the fault algorithm in the sense that some points are displaced
upwards. The main differences reside in the way how the points are select and how the points are
displaced. In the fault algorithm a line divided the terrain in two parts, points in one part where
displaced upwards, whereas points in the other part where displaced downwards. In here a circle
with a random center, and a user defined radius is computed. Points inside the circle are
displaced upwards, whereas the remaining points will keep their height.
The points inside the circle are displaced according to a cosine function as shown in the next
figure

The next image shows a single iteration.
As you can see the algorithm is very simple. The first step is to find a random point which will
be the center of the circle. Afterwards the points inside the circle are displaced using the
following pseudocode.

for each terrain point (tx,tz) do

pd = distance from circle center * 2 / terrainCircleSize

if fabs(pd) <= 1.0

height(tx,tz) +=       disp/2 + cos(pd*3.14)*disp/2;

where terrainCircleSize defines the circle size and disp defines the maximum height variation.
As in the fault algorithm, the value of disp can be decreased as the number of iterations
increases.
As usual there are endless variations to this algorithm, for instance try replacing the cosine with
other functions. As an example, in the implementation provided, for each circle the height can be
decreased or increased according to a random value, i.e. some iterations increase the height of
the points inside the circle, whereas others will produce the symmetrical effect.
The following image is a screen shot of a terrain rendered with this algorithm after 1000
iterations.
Terrain Tutorial

Mid Point Displacement

The Mid Point Displacement, MPD hereafter, aka the Plasma Algorithm, is a subdivision
algorithm. The terrain is built iteratively, in each iteration the level of detail increases. From a
computational point of view this algorithm is very inexpensive when compared to the previous
algorithms, and its results are quite impressive.
This algorithm was conceived to generate square terrains with dimensions (2^n + 1) x (2^n + 1),
where n stands for the number of iterations. This implies that with just 8 iterations a good
looking terrain with 257x257 grid points is generated. With 10 iterations we get 1025x1025 grid
points. Just be ware of the memory and performance implications, a terrain with 1025x1025 grid
points takes a lot of memory, and unless there is some real time navigation algorithm
implemented, performance will be lousy.
The most important parameter of this algorithm is the roughness constant. This value determines
the look of the final terrain, from extremelly smooth, to very rough. The most common value for
this parameter is 1.0. The images bellow show examples of MDP with various roughness
constants.

r = 1.0

r = 2.0

r = 0.5
Terrain Tutorial

Mid Point Displacement Algorithm

The Mid Point Displacement algorithm is very simple. As opposed to the previous algorithms,
the grid size of the terrain, i.e. the number of grid points increases per iteration.

Initially the algorithm starts with a 2x2 grid. The heights
of the four corners can be set to zero, a random value, or
just some preset value.

The first step is to find a height for the center of the
terrain. This value is computed as the average height of
the four corners plus a random displacement. This step
is know as the diamond step (if you render the terrain
now you'll see four diamond shapes).
E = (A+B+C+D) / 4 + RAND(d)
where RAND(d) is a random value in [-d,d]. The value
of d represents the maximum displacement in the current
iteration.

What follows is the square step. In here the midpoints between the four corners, the blue dots,
are computed as the average of the connected points plus a random displacement.
F = (A + C + E + E) / 4 + RAND(d)
G = (A + B + E + E) / 4 + RAND(d)
H = (B + D + E + E) / 4 + RAND(d)
I = (C + D + E + E) / 4 + RANS(d)

The formulas presented implicitly imply that the terrain wraps, i.e. that F = H (otherwise there
would be no wrapping). So if you want to consider wrapping, you don't actually compute the last
row and column of the grid, just take the values from the first row and column respectively.
Terrain wrapping is not a common feature since it provides noticeable repetition, and thats the
last thing you want. Nevertheless it you're using this algorithm just as a step towards the final
terrain, i.e. to provide just a little bit of irregularity to your otherwise ready terrain, then
wrapping is a good option.
In my humble oppinion, if wrapping is not going to be used in practice, then there is no
advantage in having such a feature. In fact a terrain that wraps must share topological features
between opposite borders. For instance if there is an elevation on the right side, then there must
be a similar elevation in the left side as well to allow wrapping. If wrapping is not going to be
used then this is an undesired feature. In this case I suggest that you don't wrap the terrain. For
instance to compute F use
F = (A + C + E)/3 + ...
F = (A + C + E + E)/4 + ...
Basically, for the points on the border use just the three connecting points to compute the
average.
The first iteration is complete. Now it is necessary to multiply the value of d as shown

d *= pow(2,-r)

where r is the roughness constant presented in the previous section.
Now we have four squares. The process is repeated for
each square: first for all squares apply the diamond step,
i.e. compute a height for eacg center (red points). For
instance in the figure bellow,
J = (A + G + F + E)/4 + RAND(d)
K = (G + B + E + H)/4 + RAND(d)
L = (F + E + C + I)/4 + RAND(d)
M = (E + H + I + D)/4 + RAND(d)

After applying the diamond step to all squares, it is time
to apply the square step. In the figure on the left, the
points for the first square are the blue points. The
wrapping version is
N = (K + A + J + F)/4 + RAND(d)
O = (L + A + G + J)/4 + RAND(d)
P = (J + G + K + E)/4 + RAND(d)
Q = (F + J + E + L)/4 + RAND(d)
In the non wrapping version the computation of N and O
is different:
N = (A + J + F)/3 + RAND(d)
O = (A + G + J)/3 + RAND(d)
Terrain Tutorial

Particle Deposition

I first came across this algorithm in the book "Graphic Programming Gems" (an excellent book
btw). The algorithms presented in here are a merge between the book's idea and something I saw
on the web at "Pulchritudinous Primes". Anyway, here goes.
The main idea behind particle deposition is ... particle deposition. What that means is that we're
shape of the terrain. By adding a particle, I actually mean adding a vertical displacement at a grid
point.
To start with, a random grid point (x,z) is selected. The height of the selected grid point, i.e. its y
component, is increased by a certain amount. The displacement can be constant, or a decreasing
value as we iterate.

After the grid point is displaced, we need to select another point. Use up your imagination to
select the next point, there are so many alternatives. The approach taken in here is a very simple
one, and its based on the site mentioned above: a random number between 1 and 4 is generated,
and the value represents a direction. An example is shown bellow:

v = rand();
switch(v) {
case    1:   x++;break;    //   move   right
case    2:   x--;break;    //   move   left
case    3:   z++;break;    //   move   closer
case    4:   z--;break;    //   move   away
}

Then we displace the new point (x,z) upwards. There is just a small detail now. Assume that the
particle is placed on a grid point A. Furthermore, assume that one of A's neighbours has a height
which is lower than A was before the particle was dropped. Then the particle will roll to the
neighbour. The basic idea is to get a "stable" system. With this approach the surface of the terrain
will look smooth. The other approach is to have "sticking particles", i.e. a particle stays where it
lands regardless of the neighbours heights. The sticking particles approach is more prone to
generate peaks. Depending on the effect you're looking for you may choose one of the above
approaches.
If we keep adding particles for, say 1000 iterations, we get some interesting shapes as shown
bellow:

and with sticking particles we get,

Note: In the terrains above the height was scaled up and a smoothing filter was applied.
As the figures above show the sticking particles method tends to create rougher terrains than the
rolling particles. Just one more thing, when the direction found with the method above takes you
to a point outside the terrain, I've found that is better to treat the terrain as if it wraps around,
rather than moving the point back inside the terrain. However that's just a hint, try it yourself.
As opposed to the previous algorithms, we get interesting effects when we restart. This is
because when we start over, we start with an unrelated a fresh random point, and is quite
possible that the new point will land far from the "island" shown in the above figure, therefore
creating another island. The following terrain was generated with 5 series of 1000 iterations of
the algorithm above.
As you probably figured out by now there are many possible variations on how to select the next
grid point, here are a few although I'm sure that none is original:
a) Select a point and a radius. Generate random points within the circle centered in the first point.
b) Create a black and white image with the same dimension as your terrain. Place black patches
in the image in the shape you want your islands to have. Then use that image as a filter to select
the next point, i.e. only deposit particles on the terrain if the corresponding image point is black.
c) make up your own and let me know if you get interesting results.
In the source code, namely in the terrain.cpp file, you'll find two functions directly relating to
this algorithm. The first sets the particle mode:

void terrainSetParticleMode(int mode);

Parameters:
mode - STICK or ROLL

The second function is the terrain creation function:

int terrainIterateParticleDeposition(int numIt);

Parameters:
numIt - the number of iterations to perform

```
DOCUMENT INFO
Shared By:
Categories:
Tags:
Stats:
 views: 584 posted: 2/12/2010 language: English pages: 21
Description: Terrain algorithm for make a good terrain mipmaping
How are you planning on using Docstoc?