|
Players
today demand a rich game experience with larger worlds to explore, more
interesting things to do, and higher degrees of realism with each new
title that ships. The problem is that game development schedules and
budgets cannot keep pace with consumer demand for new feature sets.
So, how do we make larger, more interesting worlds without blowing milestones
and spending large sums of money? Simply put, we must have some of our
game data generated automatically for us.
For example,
suppose you're developing an online massively-multiplayer game with
an enormous amount of polygonal terrain (hundreds of thousands of screens'
worth of in-game scenes) for thousands of players to exist in and interact
upon. In addition to that (just to make your life more difficult), this
terrain model must conform to a loose, preexisting map specification
(in other words, the general map layout and major landmark locations
are known relative to each other, but there is no concrete data set
describing the terrain, such as satellite imagery). This constraint
eliminates the possibility of using any truly automatic terrain generation
algorithm (such as fractal terrain generation). Meticulous construction
of the terrain model by artists' hands is completely out of the question.
No group of artists assigned this arduous task would be able to produce
the desired result within the budget constraints; it will either cost
a prohibitive amount of money, or take more time than is allotted for
the development of the product. So you're left searching for some kind
of middle ground between these two extremes.
Using
manageably-sized, artist-generated bitmaps, combined with some clever
image processing techniques, you can create a desirable terrain model.
The techniques I describe in this article don't eliminate artist or
world-builder involvement from the creation process - these techniques
only create a model that is very close to completion in a relatively
short amount of time. Once generated, the terrain must be fine tuned
by an artist or level designer to add the aesthetically pleasing final
touches.
There
are several other advantages to using bitmaps for your terrain modeling.
First and foremost, the tools for manipulating images (such as Photoshop)
are extremely well developed and well known by a majority of artists.
Second, the techniques I'm about to discuss will lower the ratio of
time spent generating the terrain images to the amount of in-game data
you can generate from them. Finally, this technique lets you view the
layout of the entire world within a fairly small area - the bitmaps
we will use are fairly manageable and allow you to view the entire image
at once on a typical monitor.
 |
 |
|
(Left) Figure
1a. Scaled terrain bitmap. (Right) Figure 1b. Scaled and smoothed
terrain bitmap.
|
It's assumed
that the terrain model desired is a textured 3D polygonal mesh, with
the vertices lying upon a regularly-spaced rectangular grid. The terrain's
z-values (the "up" vector) are taken from a two-dimensional
array of values called a height field. The terrain textures are also
set according to a two-dimensional array of values, where different
values denote specific types of terrain. This helps specify a texture
to use for a particular cell in the terrain grid. Thus, two bitmaps
are required to generate all the data needed to create terrain. In the
examples provided in Figures 1a-b and 2a-b, the height and terrain data
bitmaps are 8-bit grayscale and palletized color images, respectively.
 |
|
Figure
2. Scaled elevation bitmap.
|
Note that
there are several methods by which you can use this terrain data to
create a system of connecting tiles. For example, you could view each
terrain value as an individual tile, or view each value as a tile vertex,
and so on. However, this article is strictly concerned with generating
the needed data. Showing you what to do with the data once it has been
generated is beyond the scope of this article.
Bitmap
Representation of Terrain and Elevation Data
Translating
bitmap values into usable data is straightforward, assuming you can
read the file format of the bitmap. For a given entry (x, y) in a height
data bitmap, a corresponding value in the height field can be calculated
by taking the value in the bitmap and multiplying it by some scalar:
heightField (x, y) = bitmap (x, y) · scaleZ. Using the terrain
bitmap is even easier. Since the bitmap is 8-bit, simply set the value
(palette index) at any given point (x, y) in the image to a predetermined
terrain type. If more than 256 terrain types are needed, you can use
the RGB values of a 24-bit image for terrain type indexing instead.
While
the goal is to use a large data set to generate a terrain model, it
is unlikely that a 1:1 mapping of bitmap values to height and terrain
values will yield a large enough data set for very large game worlds.
Thus, you probably will have to "scale up" the bitmaps some
way in order to generate sufficient amounts of data.
There
are two easy ways to scale the data gathered from the height bitmap.
The methods rely on a two-dimensional scale vector (scaleX, scaleY)
to do the work. The scale vector is created based on the ratio of the
size of the bitmap to the size of the terrain model one wishes to create
from the bitmap.
The first
method takes each pixel (x, y) in the height bitmap and duplicates the
pixel value bitmap (x, y) inside a rectangular area of pixels scaleX
· scaleY in size, in which the upper left corner of the rectangle
equals (x · scaleX, y · scaleY). Empirically, the data
becomes "pixellated," as though the bitmap is viewed at a
higher zoom level. The terrain data is scaled in this way, as well.
The second
method of scaling the height data treats the bitmap values as points
on an arbitrarily large surface, or as control points used to generate
such a surface parametrically, in which each value in the height bitmap
is a discrete sample from this surface. For a given entry (x, y) in
one's height-data bitmap, a corresponding value in the height field
can be calculated using the following mapping function:
x, y,
bitmap (x, y)] = [scaleX · x, scaleY · y,
 scaleZ
· bitmap (x, y)]
All we're
doing is taking a point in the height data bitmap and multiplying it
by a scale vector of (scaleX, scaleY, scaleZ).
 |
|
Figure
3a. Scaled, unfiltered height data.
|
Now that
the amount of raw data needed to create the full size terrain model
has been generated, one might notice (see Figures 1a-b, 2, and 3a) that
scaling the bitmaps has created some rather harsh and unwanted artifacts
in the final images. To correct these artifacts, let's use some basic
filtering techniques from the field of image processing.
|