Sunteți pe pagina 1din 60

Free Project Tile Based Terrain Engine

Author: Email: Date: Version:

E.J. Folkertsma (s0002631) e.j.folkertsma@student.utwente.nl 03-05-2004 1

Acknowledgements
Firstly thank you to all people who played with my application in order to see whether it worked, how it worked and for giving tips on how to improve the stuff: Andy Vickers, for being very interested in the work I did leading to multiple (long) conversations which made me realize how to build stuff often, mental support and application testing. Arjan Pragt for testing my application and providing lots and lots of negative feedback through the years which motivated me to keep on programming until perfection Pieter Bos, mainly for supplying the idea that feathered brush tiles should be have their feather factor for transparency. The people at Kung-Fu, especially Sebastiaan Blom, for sticking up with me talking about my project way too much. Most importantly a BIG thank you to my girlfriend: Che Bich Quynh Nhu (also known as Lyly. And sorry sweetie that I cannot write the name entirely correct with the bars over the letters, but Word just does not support that) for sticking up with me programming most of the time and you having to come over to my place to do work here. Finally I wish I could send out a big thank you to websites such as www.opengl.org, www.flipcode.com, and www.gamedev.net, but as it turned out the contents of these websites were too basic to be used at all. However, a big thank you goes out to the people of the websites of www.boost.com, www.dinkumware.com and www.cplusplus.com for providing easy to use and (more importantly) accurate libraries and library descriptions. Ebor Jan Folkertsma

Legal Information
The names of all companies, organizations, product, domain names, e-mail addresses, logos, people, places and events mentioned in this document are either patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. I used information from the following websites: Warcraft III: Reign of Chaos is property of Blizzard Entertainment URL: http://www.blizzard.com/war3 Command & Conquer Generals is property of EA Games URL: http://www.eagames.com/official/cc/generals/us/home.jsp Emperor: Battle For Dune is property of EA Games URL: http://www.eagames.com/ Microsoft Visual Studio .NET is property of Microsoft URL: http://www.microsoft.com/ Doxygen GNU General Public License Copyright 1997-2004 by Dimitri van Heesch. URL: http://www.doxygen.org/ DevCPP is property of BloodShed Software URL: http://www.bloodshed.net Borland C++ Builder is property of Borland URL: http://www.borland.com MilkShape3D is property of ChumbaLum Soft URL: http://www.swissquake.ch/chumbalum-soft 3D Studio Max is property of Discreet URL: http://www.discreet.com GIMP is GNU URL: http://www.gimp.org Adobe Photoshop is property of Adobe URL: http://www.adobe.com The names of actual companies and products mentioned herein may be the trademarks of their respective owners.

General Information
All the 3D imagery presented in this document is created by using either premature demo material I created, end result material I created, or by using a (free) 3D modeling program. This means that the actual product sometimes looks different than the illustrations found in this document. I did not include graphics for the games/programs I mention in this document since that would require me to request authorization from the companies that own these products, which seems to be a long term process. For images related to those products I encourage you to visit their websites, which are listed in the Legal information chapter. The document contains a lot of images for illustration and most of these images are quite large as well. In my view I could not include less or smaller images without severe consequences regarding the reader to understand what I meant. Most of the images are also in color and a grey scale of the image will not show the right amount of detail to understand what I explain. Therefore it is recommended to view this document in either a color print or on-screen.

Contents
Acknowledgements ......................................................................................................... 1 Legal Information ........................................................................................................... 2 General Information ........................................................................................................ 3 Introduction .................................................................................................................... 6 Motivation ...................................................................................................................... 7 Code ............................................................................................................................... 8 Code Component Structure ............................................................................................. 9 Terrain Version 1 ........................................................................................................ 9 Terrain Version 2 ...................................................................................................... 10 Terrain Editor................................................................................................................ 11 Camera...................................................................................................................... 11 Brushes ..................................................................................................................... 11 Deforming the terrain mesh ....................................................................................... 12 Applying tile textures ................................................................................................ 12 Terrain .......................................................................................................................... 15 Internal structure (both versions) ............................................................................... 15 Point Map (both versions) ......................................................................................... 15 Tile Map (both versions) ........................................................................................... 16 Basic tiles (both versions).......................................................................................... 17 Complex tiles (not implemented)............................................................................... 17 Tile Structure (first version) .......................................................................................... 18 Tile Graphics............................................................................................................. 18 Tile Graphic Layering ............................................................................................... 19 Tile Graphic Collections............................................................................................ 20 Tile Graphic Sets....................................................................................................... 21 Tile Structure Problems (first version)........................................................................... 22 TileGraphic mismatching .......................................................................................... 22 TileGraphicCollection texture layout......................................................................... 23 Tile Structure (second version)...................................................................................... 24 TiledTexture.............................................................................................................. 24 TiledTexture layering ................................................................................................ 25 Tile Structure Problems (second version) ...................................................................... 27 Too many textures..................................................................................................... 27 Color Blending Artifacts ........................................................................................... 28 Triangle Blending Artifacts ....................................................................................... 29 Tile Blending Artifacts .............................................................................................. 30 Tile Storage............................................................................................................... 34 Rendering speed ........................................................................................................ 36 Visibility processing (both versions) ............................................................................. 38 2D (Normal) Quad-tree ............................................................................................. 38 3D Quad-tree............................................................................................................. 38 Lighting the terrain........................................................................................................ 39 Per-Vertex-Lighting (both versions) .......................................................................... 39 The implementation of Per-vertex-lighting ............................................................ 39

Shadow Mapping (version 2)..................................................................................... 40 The implementation of Shadow mapping............................................................... 41 Shadow Mapping problems (version 2) ......................................................................... 46 Ray-tracer problems .................................................................................................. 46 Generic Problems .......................................................................................................... 49 Brushes ..................................................................................................................... 49 Texture Loading ........................................................................................................ 49 Texture Compression ................................................................................................ 50 Features that did not make it.......................................................................................... 51 Meshes ...................................................................................................................... 51 Water ........................................................................................................................ 53 Conclusion / Evaluation ................................................................................................ 54 Code ......................................................................................................................... 54 Theory....................................................................................................................... 55 General ..................................................................................................................... 55 Results ...................................................................................................................... 56 Appendix A: System specification................................................................................ 57 Required.................................................................................................................... 57 Recommended........................................................................................................... 57 Appendix B: Development tools specification ............................................................... 58 Appendix C: References................................................................................................ 59 Books........................................................................................................................ 59 Websites.................................................................................................................... 59

Introduction
This document describes the free project I did for my 4th year of Computer Science at the University of Twente. The project as it yields 4 study points (equal to approximately 5.7 ECTS, equal to 160 hours), since 3D computer graphics tend take up a lot of time while developing. Doing the project for less study points will seriously diminish the amount of features, since building the core of the engine will take up the major part of the time. Adding features to it is then less work and can be done quite rapidly, which will result in a more complete engine as a whole. I based this study point amount on my previous experience with these kinds of projects. I created two versions of a 3D tile based terrain game engine. This means that instead of the more usual Computer Science related terrain engines, which are based on some Level Of Detail (LOD) algorithms, the terrain will consist out of rectangular tiles. The engine supports deformation of the terrain mesh and placement tile textures on the terrain. All this functionality should is supported by a terrain editor I developed, which is the main application. Though the engine will be a game engine, as stated above, the application I have developed is a terrain editor. I did not create an explicit game, since that would require many other aspects such as game-play, artificial intelligence, path finding, etc which is beyond my capabilities given the time frame.

Motivation
A 3D tile based terrain game might look strange from the viewpoint of a Computer Science course, since in general people doing a comparable assignment will opt for a terrain engine that uses Dynamic Mesh LOD. I have my own reasons however not to choose for such a type of engine which I will motivate now. First of all, in my opinion building a terrain engine that uses Dynamic Mesh LOD (DMLOD) is not as creative as I would like it to be. I will not say that creating a DMLOD terrain is not creative at all, since from the programmer s point of view there might be a lot that can be done in several ways, forcing the programmer to think of a creative solution. But in my eyes doing such a project is basically implementing an algorithm invented by other people (for example: ROAM or Bin-Triangle-Trees) and building your own extensions to it. Instead I would like to develop my own kind of terrain tile based engine. Note my own , because a lot of stuff has already been accomplished in 3D computer graphics and my ideas are probably done before in some form. The second reason for choosing this type of engine is that in the future I would like to work in the game industry. 3D tile based terrain engines are emerging in current games, as Real-Time Tactical/Strategy games switch from 2D to 3D with the increasing processing power of current day 3D graphic accelerator cards. For example: Warcraft III: Reign of Chaos, Command & Conquer Generals and Emperor: Battle for Dune are just a few recent games employing 3D tile based terrain engines with great success. Gaining experience with the proposed type of engine is actually a good candidate for putting on my portfolio list when I want to show my work to a game company in the future.

Code
I start with the code because it gives some insight about the software components which in effect makes it easier to understand the other sections. The code for the project consists out of two home-made engine components: Vision engine Tile Terrain engine

The Vision engine is a generic engine with functionality for many different kinds of applications (not necessarily games). It was built as a base layer on which the TileTerrain engine is built. Development of the Vision engine was, for the major part, simultaneously with the implementation of the TileTerrain engine. The Vision engine is subdivided in several components: Common DataTypes FileSystem Math RenderSystem

The Vision engine components are based on well know principles such as Data structures, Files, Rendering (OpenGL based), which I consider unrelated and mostly trivial. Therefore I will not deal with that code at all in this document, the documentation for this is on the CD in the form of Doxygen generated HTML manual (see the readme.txt file on the CD s root for more information.) For both versions of the TileTerrain code I will show a rough component wise interaction diagram to let u gain some insight in how everything works. Note a rough component wise interaction because I noticed that the full diagram is not very helpful at all, since the design involves a lot of class interactions. For more information regarding to the functionality I point you to the Doxygen generated HTML manual (see the readme.txt file on the CD s root for more information.) For future extensions to the code it is handy to have a code style so that adaptations are in the same style. I did not include the code style in this document as this document only focuses on the ideas I used, not the actual implementations. The code style can be found on the CD in the Documentation/Engine Usage directory with the filename Code Style.doc (see the readme.txt file on the CD s root for more information.)

Code Component Structure


Terrain Version 1
Borland C++ Builder GUI Application

TileTerrain Game Engine (ver 1)

Camera

TerrainEditor

Brush

Visible tiles

Terrain

QuadTree

ElevationMap

TileMap

Environment

ElevationGrid

Weather

NormalGrid

Sun

Figure 1: Code Component overview of TileTerrain version 1.

Terrain Version 2
Borland C++ Builder GUI Application

TileTerrain Game Engine (ver 2)

Camera

TerrainEditor

Brush

Terrain

Sun

PointMap

TileMap

Visibility

ColorGrid

TileGrid

QuadTree

ElevationGrid

Visible tiles

NormalGrid
Figure 2: Code Component overview of TileTerrain version 2.

10

Terrain Editor
This chapter deals with some quick information to understand the terrain editor, which is the best way to see what I mean when I am explaining graphical things.

Camera
Viewing the terrain is done using a camera. In the terrain editor the camera can zoom in / out, pan and rotate. The camera is controlled in the terrain editor application by both scrollbars and by mouse commands. Rolling the mouse-wheel up provides zoom in, rolling the mouse-wheel down provides zoom out, holding the mouse-wheel down while dragging the mouse to the left or right makes the camera rotate and holding the rightmouse button while dragging the mouse pans the camera.

Brushes
All operations on the terrain are based on a concept I call Brushes. The level editor uses brushes to deform the terrain mesh and to apply tile textures to the terrain. Brushes basically are regions following the contours or the terrain. A Brush consists out of a solid and a feathered part. The solid part performs 100% affection of the desired operation. The feathered part performs X% affection of the desired operation, where X is based on the distance to the solid part of the Brush. Figure 3 shows the visual appearance of two Brushes.

Figure 3: Brushes The left side is a square brush. The right side is a round brush. Each brush is made up out of rectangles that will follow the contours of the terrain. When applied the green portion of the brush will apply the total effect of the brush s function and the blue portion of the brush will apply only a percentage of the effect the brush s function. The amount of intensity of the blue part indicates this percentage. This gives in the terrain editor a quick overview of what the result of applying the brush would be. The green area of the brush is called the solid brush. The blue area of the brush is called the feathered brush because it acts like it is feathered.

Note that the solid and / or feathered size can and sometimes must be zero, but at least one of them has to be non-zero for any effect to occur.

11

Deforming the terrain mesh


The terrain mesh can be edited by setting an elevation value for the vertices that make up the rectangular tiles. The brushes have a function attached to them which each manipulates the terrain in its own way. The following brush functions are supported: Lowering the terrain Raising the terrain Plateau the terrain (Set elevation for the terrain) Smoothing the terrain Noise the terrain (Randomly adding values to the vertices)

Each brush function has a strength parameter that can be adjusted to alter its influence. For example, the Lowering the terrain function has a parameter that specifies the strength of the lowering. The Jittering the terrain function has a parameter that specifies the strength of the roughness of the terrain. The other brush functions have comparable parameters. See Figure 4 for an example of applying the Raising the terrain brush for the brushes specified in Figure 3.

Figure 4: Terrain mesh deformation The left side shows the application of the square brush from Figure 3. The right side shows the application of the round brush from Figure 3. The solid brush parts effect the terrain deformation completely. This results in a plateau style of terrain with nice interpolated sides that lead up to it.

Applying tile textures


The application of texture to the tiles works the same in both versions of the terrain editor even though the tile algorithms themselves differ. Although brushes are use to place the tiles it is important to note that only the solid part of the brush is used for placing tiles. This is because the blending of the tiles is on a per tile basis and is automatically determined by the terrain editor.

12

The actual usage and result of the tile application is quite different between the two versions. In version 1 the usage is based on selecting a TileGraphicCollection and using either a random or selected TileGraphic. The result is the image below.

Figure 5: Tile texture application for terrain editor version 1

In this image one can see the individual grass leaves hanging over the dirt (brown) surface. The grass tiles them selves are decorated, in the image above one sees a stone, some yellow flowers and some dirt in the grass. Although this image uses about eight tiles in width and six in height it does not show any repetitive patterns. That is because the Random checkbox gives different graphics for the tiles. Terrain editor version 1, therefore the image above, is based on untiled alpha textures (It is not of importance that you do not understand yet what this means, just keep it in mind).

13

The second version of the editor offers far more possible textures for the tiles (I will explain why later). Selecting a texture consists out of selection a texture from the texture list or selecting a slot from the texture palette and then applying the brush to the terrain, the result is shown below.

Figure 6: Tile texture application for terrain editor version 2

In this image one cannot see details like grass leaves hanging over like in figure 5. Instead of the crisp edges in figure 5 this figure blends the tiles over into each other. Further more this image also uses about eight tiles in width and six in height, but it does show some repetitive patterns already. If you look at the dark spot near the bottom-right of the image, you will see that same pattern 2 times more; in the top-left en in the topright part of the image. Note that the image is a bit distorted because we look at the tiles form a 30 degree angle. Terrain editor version 2, therefore the image above, is based on tiled (non-alpha) textures (It is not of importance that you do not understand yet what this means, just keep it in mind).

14

Terrain
This chapter deals with how the terrain works. I made two versions I will describe both and then discuss the differences between them. Because both types of terrain share some commonalities I will describe these only once and I will indicate per feature to which version it belongs between parentheses per section, these can be (first), (second) or (both). The main purpose of this document is to describe the ideas associated with real time terrain rendering of game related terrains. This implies that a fair amount of explanation is concerned with optimizing certain data structures.

Internal structure (both versions)


It is vital for a correct understanding of this document that you know how the coordinate system works. The terrain uses a right handed coordinate system. In that system it uses the x axis for specifying the tile s x coordinate and the z axis for specifying the tile sy coordinate. The y axis is used on the ElevationMap for the elevation of the terrain. I will not explicitly differentiate between these two coordinate systems, as it is very clear when I mean which system. Further it is important to know how the first version and the second version of the terrain work. Although this will be dealt with in detail one should know upfront that the first version uses untiled alpha textures (see figure 5) and the second version uses tiled (nonalpha) textures (see figure 6). (It is not of importance that you do not understand yet what this means, just keep it in mind.) The terrain is based upon two maps: point map and tile map, which I am going to discuss in the next two sections.

Point Map (both versions)


The point map part of the terrain indirectly deals with the vertex information, except texture coordinates, for rendering the terrain. Note indirectly because the most important component, the ElevationGrid, which is used for generating vertex positions does actually not store (x, z) coordinate components, since these can be derived from the tile coordinates (tile_x, tile_y). The first version of the terrain contained the following point map components: ElevationGrid NormalGrid

15

The second version of the terrain contained the following point map components: ElevationGrid ColorGrid NormalGrid

The ElevationGrid stores elevation information and deals with all operations that manipulate the elevation of the terrain. In the versions I made the elevation values range from 0.0f to 16.0f with a precision of 1.0f / 16.0f. This enables you to load / save the elevation data from / to a grey scale image (not supported by the terrain editor, supported in the code though). It is possible to change these values in future adaptations very easily. The ColorGrid (second version only) stores per vertex color information, calculated based on the sun s color and the NormalGrid, which is required in the rendering process (see Problems: Color Blending Artifacts for more information). The NormalGrid stores per vertex normals that are used to calculate per vertex color. In the first version the normals are simply fed to OpenGL which determines the per vertex color. In the second version the normals are only required for determining the values of the vertex colors in the ColorGrid component, the game version of the terrain does not have to include this information. The PointMap s (or ElevationMap for version 1) purpose is to encapsulate all elevation based operations in a single class. This is required because changing for example the ElevationGrid requires recalculation of the NormalGrid and ColorGrid. Further more all operations on the terrain mesh are in the form of a Command which only needs to store parts of the data to (un)execute. Thus calling a method of the PointMap class handles all calls to the Elevation / Color / Normal-Grid classes so that internal consistency is assured.

Tile Map (both versions)


The tile map deals with all tile based operations in the same manner as the PointMap deals with all point based operations. In the first version of the terrain I used the TileMap directly for all tile operations, but as this broke the style of how the components worked together I made a TileMap TileGrid relation. This relation also provides more extensibility in case you need to extend the tile system to support different types of tiles (see for example the Complex Tiles Section). As said above, the first version of the terrain contained no tile map components, as it was the main component itself. In the second version of the terrain the TileMap component only has the TileGrid component which contains all basic tiles as described next.

16

Basic tiles (both versions)


The terrain is composed out of a rectangular grid of tiles that are created between vertices. The vertices have a constant delta distance in the x and z axis, but their elevation (on the y axis) can vary, which gives an elevation based terrain.
Figure 7 A small piece of terrain consisting of a grid of four by four tiles. Each tile is a rectangular tile. Rectangular because the elevation differences for each vertex* cause the tiles to be bended in a particular way. * The vertices are located at the intersection points of the wire-frame

Complex tiles (not implemented)


Complex tiles are meshes that have the same dimensions (in the x and z axis) as a basic tile, but they contain more mesh data in on one / all axis. Complex tiles provide an interesting way to decorate the landscape and break the uniformity. This does not mean that the complex tiles are just decoration of the terrain, in the contrary. They act more or less like normal terrain. That means that units can traverse the terrain on some parts of the complex tiles. For example, if you look closely at the top of the rock in Figure 2, you will see that it is green indicating that rectangular tiles are on top of it. However, when units try to climb up the rock directly will not succeed, since the sides of the rock (which is a complex tile) acts as a clipping object which disallows units to pass it that way.

Figure 8 The same terrain as in Figure 7, but this time with some complex tiles on the terrain. The tiles in the front are rectangular tiles. The other tiles that make up the mountain are complex tiles that actually are complex meshes. This can be seen by the much higher density of the wire frame for the complex tiles.

The complex tiles are be predefined meshes that have some properties that will make them blend into the terrain naturally. For a very good example of this concept, see the Warcraft III: Reign of Chaos WorldBuilder level editor application.

17

Tile Structure (first version)


This chapter describes the composition of the terrain for version 1. First I will explain the concept of TileGraphics, which are basically used to texture the terrain. In order to fully understand the usefulness of TileGraphicCollections, one should understand the layering of tile graphics concept. This concept is therefore treated right after the TileGraphics section. Finally I will discuss TileGraphicSets which are used to stuff multiple TileGraphicCollections into a set that can define a certain theme. The next sections are as follows: Tile Graphics Tile Graphic Layering Tile Graphic Collections Tile Graphic Sets

Tile Graphics
TileGraphics are images that are placed on the tile rectangles of the terrain. Each TileGraphic has dimensions of 64x64 pixels and is stored as a 24 or 32 bit image which is called a TileGraphicCollection. Currently it is only important to understand that a TileGraphic is (a portion of) a texture. The application of TileGraphics to the terrain is based on the Brush that affects the terrain (note that only the solid part of the Brush is used when altering the Tile Graphics). See Figure 9 for a thorough visual explanation.
Figure 9 This figure shows a 4x4 tile grid snapshot. The red lines indicate the Tile rectangles. The blue points indicate the vertices, out of which the terrain mesh consists, that make up the Tiles. The green square in the centre represents the solid part of the Brush. The background contains grass. When the user applies the brush to the terrain (while in change Tile Graphic mode) all Tiles touched by the green square, these are the numbered 1,2,3,4, will be affected. How they are affected is explained in the Tile GraphicCollection section.

18

Tile Graphic Layering


Each tile in the terrain can be textured by using a specific TileGraphic. Different types of Tile Graphics are not interpolated or blended as some like to call it. (Version 2 and Command & Conquer Generals do that) Each individual tile can contain up-to-andincluding five different Tile Graphic layers. The layering technique is used in both Emperor: Battle For Dune and Warcraft III : Reign of Chaos . Figure 10 shows the effect for a base layer consisting out of grass with some street like tiles layered upon it.
Figure 10: Tile Graphic Layering This figure shows a 5x5 tile grid snapshot, the red lines indicate the Tile rectangles. The base layer contains grass. The centre portion is made of street tiles. In the centre of the street portion you see some street like tiles that cover the grass tiles totally. This means that the engine does not render grass tiles below these tiles. The edges of the street tile portion are constructed by using two layers. The lowest layer contains the grass texture. The top layer contains the border textures for the street tiles. Because the borders actually use two textures, the tile rectangle will be rendered twice (this is not entirely true, as multi-texture hardware can do it in a single pass, but this is not yet supported by the engine).

The layering method requires each TileGraphicSet (for more information see the: TileGraphicSet section) to have a layer order for each TileGraphicCollection. For example: Suppose that you have four types of TileGraphicCollections in your TileGraphicSet: Dirt, Grass, High Grass and Street. The layer order is: Dirt = 1, Grass = 2, High Grass = 3 and Street = 4. The base layer is Dirt (= 1). This means that placing any of the other three types of tile graphics on it will make them appear above the dirt. Street (= 4) Tile Graphics are the top-most graphics that will appear to be above everything else. In Figure 10 the Street TileGraphicCollection has a higher layer order so that it appears to be on top of the grass. Using this technique the worst case scenario is a tile with a base layer and on it four different TileGraphicCollection on each edge. This will result in a total of five layers to be rendered which is quite slow.

19

Tile Graphic Collections


To support the TileGraphic layering method as described above, we need a collection of centre and corner TileGraphics, this is the TileGraphicCollection. The centre tile graphics are those that totally cover the tile. The corner graphics are the graphics that do not totally cover the tile and therefore are layered upon the base layer. Figure 10 illustrates both types of tile graphics. In order to be able to render all possible combinations of tile graphics we need at least one centre graphic and fourteen corner graphics. Figure 11 shows which types are required. 1 0 0 1 1 1 0 0 1 1 0 0 0 0 1 0 1 1 0 1 0 0 1 1 0 0 1 0 0 1 1 0 0 0 0 1 1 1 1 1 1 0 0 1 1 0 0 1 1 1 1 0 1 0 0 1 0 1 1 1

Figure 11: TileGraphic layering template This will be explained by help of figure 9. In figure 9 there are four tiles that are numbered: 1, 2, 3 and 4. In this figure you see squares filled with binary numbers. The binary numbers can be transformed to decimal numbers by using the following scheme. Top-Left square is 2^0, top-right is 2^1, bottom-left is 2^2 and bottom right is 2^3. The binary cells correspond to the four vertices used by each rectangular tile. The black color indicates that the currently selected TileGraphicCollection is used there. So if you would apply the brush as it is in figure 9 (with a different TileGraphicCollection than grass) the tile with number 1 would have the TileGraphic layering template with number 9 (the centre one in this image) and the tile with number 2 would have the TileGraphic layering template with number 1 (the top left one). From this it is note hard to see that there are 2^4 = 16 possible TileGraphic templates. We can skip the one with all zeros however since that would mean that only the base layer is showing. That leaves 14 corner graphics and at least 1 centre graphic.

The fourteen corner graphics and at least one centre graphic amount to fifteen images in total. The fourteen corner TileGraphics are required just in case you build a level that

20

needs them all, even the more exceptional ones. The corner TileGraphics offer just a single image for each possible combination. Offering more images for each combination might sound tempting, but reality shows that it requires too much memory from the video card. Even though this single image restraint might seem very harsh, practice has shown that it is possible to create very nice looking terrains with only single images for the corner Tile Graphics (for example see some of the maps in Warcraft III: Reign of Chaos). Key to the success is not allowing the terrain to have the same border repeating over and over for more than three or four times. I will not go further into this, because it has nothing to do with the engine, but more with the creativity of the terrain designer. Only having a single centre TileGraphic that will be used on every tile that requires complete coverage of the TileGraphic makes the terrain look boring again. Therefore the engine supports multiple centre TileGraphics. Each of these graphics should be slightly different. An example of this is shown in Figure 12 Figure 12, which shows two types of centre Tile Graphics for the Street Tile Graphic Collection. For Two centre Tile Graphics to make the terrain look less monotonous. The an example of less monotonous terrain see Figure red lines indicate the Tile Graphic 10 in the section: Tile Graphic Layering, which uses rectangles. the centre Tile Graphics presented in Figure 12. This technique avoids the visually disturbing effects of seeing repetition in the TileGraphics, when used appropriately. Yet again this is actually the terrain designer s task so I will not go into this subject.

Tile Graphic Sets


By using TileGraphicCollections we apply TileGraphics to the terrain. As stated earlier the layering technique requires some layer order associated with a TileGraphicCollection. This is where the Tile Graphic Set comes in to play. A TileGraphicSet basically is a list of TileGraphicCollections. It dictates which types of TileGraphicCollections you can use while editing the terrain and which layer order they have. The TileGraphicSet also categorizes your look-and-feel of your terrain. For example: you might create a TileGraphicSet that contains three types of summer related graphics: Dirt (=1), Grass (=2) and Street (=3). You also have another TileGraphicSet with three types of winter related graphics: Muddy Snow (=1), Snow (= 2) and Snowy Street (=3). Now you can interchange the TileGraphicSets to make your level look like it was either summer or winter (this is not directly supported by the level editor). Note that this feature requires some before-hand thinking of the level designer, since the mapping from one TileGraphicSet to another is a mapping from layer order to layer order.

21

Tile Structure Problems (first version)


TileGraphic mismatching
With TileGraphic mismatching I mean that the TileGraphics for two different tiles do not blend seamlessly. This arises from the fact that the TileGraphicCollection (which stores all the TileGraphics) might have slight color differences between the TileGraphics and also some slight pixel offsets cause this (also see the TileGraphicCollection texture layout section for more information). The result is visually disturbing (see figure 13 below). Fortunately the visually disturbing effect only occurs when zoomed in very close and that will not happen very often in the game. Note that even professional software like Warcraft III : Reign of Chaos suffers from this.

Figure 13: TileGraphic mismatching Visually disturbing lines between the TileGraphics because the TileGraphicCollection texture might have some color differences for each TileGraphic.

22

TileGraphicCollection texture layout


I opted to store all TileGraphic images on a single Texture, the TileGraphicCollection texture. I did this, because of two reasons: (1) OpenGL stores name, parameter, etc; related data for each texture and less of them saves some memory according to the OpenGL specification. (2) Because it is a single texture I can use texture filtering for the complete texture which softens the edge transitions. This is especially visible for the complete covering TileGraphics (type 15 in the TileGraphic templates figure 11). Unfortunately this method has a sincere drawback as well: The alpha channel of the texture is filtered also, which results in partially transparent edges for the neighboring TileGraphics. I could have set the texture filtering to nearest pixel and the problem would have been solved then, but that would give the pixels a squared look and with some smart texture layout I did not have to do that. The texture layout will be given in two forms: graphical form (figure 14) and TileGraphic template table (figure 15).
Figure 14: TileGraphicCollection texture layout The composition of a TileGraphicCollection texture. The texture is 256x256 pixels (32bpp). Note that this texture has only two centre pieces. For texture with more centre pieces the texture size will be 256x512 and the remaining centre pieces will be added on the bottom side of the texture.

Figure 15: TileGraphicCollection TileGraphic templates

layout

for

13

10

12

The generic composition for TileGraphicCollection textures. The texture is 256x256 pixels (32bpp). Note that this texture has only two centre pieces. For texture with more centre pieces the texture size will be 256x512 and the remaining centre pieces will be added on the bottom side of the texture. To use this new layout I built a translation table that fetches the right TileGraphic from the TileGraphicCollection.

11

14

15

15+

23

Tile Structure (second version)


The first version of the terrain was visually nice enough, but the creation of the texture for that type of tiling was a nightmare, hence I had to look for a better solution. The game Command & Conquer Generals uses another type of tiling based on blending several textures on the edges.

TiledTexture
1 2 3 4 1 2 3 4 As I stated before the second version of the TileTerrain works with tiled textures without alpha channel. In version 1 the a TileGraphics are the rectangles in the b texture (the TileGraphicCollection) which are applied to the tiles. In version c 2 we no longer deal with TileGraphics / TileGraphicCollections / TileGraphic- d Sets. There is a TiledTexture which a gives the texture coordinates for the tiles based on the tile s position relative to b the world s starting point (x = 0 and z = 0). When a texture is tiling over four c tiles for example (as in figure 16) the texture is repeated every four tiles. This d requires the textures to be tileable or in Figure 16: TiledTexture other words the texture should be able to wrap around. Fortunately tileable The top 1, 2, 3, 4 indicate the repetitive pattern over textures are the most common format the textures x axis, the a, b, c, d indicate the for textures in the 3D graphics scene. repetitive pattern over the textures y axis. The red The process of creating tileable texture lines indicate the tiles. of photographs is also a quite easy process and therefore using this format does not raise the obstacle of texture creation that version 1 does.

The thing that should be determined for this method is over how many tiles a texture tiles. There are two possible approaches for this: (1) Using the texture s size and dividing it by the number of pixels per tile on both the texture s x and y axis. (2) Deriving the tileability by loading it from an external resource. Because textures must have dimensions that are powers of two, option 1 does not provide much freedom. In my case I used 64 texels per tile which leaves me to use the following texture sizes: 64 = 1 tile, 128 = 2 tiles, 256 = 4 tiles, 512 = 8 tiles and 1024 = 16 tiles. It is clear from this that this method does not exhibit much flexibility with regard to the number of tiles a texture occupies. Therefore I choose for option 2 and I use the texture s filename to determine the virtual texture dimensions. I prefix the texture s filename with the number of pixels I want it to be in width followed by a # character, for example 256#Grass.bmp. This 24

method allows me to actually store more detail on some tiles, for example if I have a texture 64#Detail.bmp which actually uses 256x256 pixels these are going to be mapped on a single tile nevertheless providing much detail for the tiles textured with it. The big disadvantage of this method is that the textures will always repeat the same relative to the world s origin. This does not pose a problem however, since the viewer hardly ever knows it s position relative to the world origin and blending with other types of textures (that are almost the same) makes it virtually impossible to see this. For the Terrain editor I needed to group the textures together so that finding which one to use was easy. To that goal I also used the TiledTexture s filename, the format is <size>#<category><number><alpha>, where <size> is the required size of the textures (not the actual size) used to determine over how many tiles it repeats. <category> is the category as found in the terrain editor. <number> is a two digit number indicating the number of the texture. <alpha> is a single alphabetical character to indicate the sub group, these subgroups are used in the terrain editor so that it is easy to see which TiledTextures blend well into eachother.

TiledTexture layering
The layering of the TiledTexture happens in almost the same way as described in the TileGraphic layering section. There are some differences however which I will discuss now. First of all TiledTextures do not have a specific layer order. In the first version the layer order was used to determine which type of graphics lay on top of another. Version 2 uses blending between two textures as can be seen in figure 17. This way of interpolation is the same in all layering orders (for example applying a dirt texture on top of a grass texture yields the same result as applying a grass texture on top of a dirt texture) making the layer order, hence the TileGraphicSet, redundant. Note that this is the same technique as used by Command & Conquer Generals .

Figure 17: Blending TiledTextures This figure shows a blending between two types of TiledTexutres: Dirt (on the left) and Grass (on the right)

The blending between the tiles uses the same system as the TileGraphic templates described in figure 11, but this time the binary values for the edges are not used to calculate the right TileGraphic. The binary values now stand for the alpha value of the vertex on that corner. By using Gouraud shading for interpolating the color, hence alpha, values between the vertices this produces a 0%-100% blend between vertices with alpha

25

= 0.0f and alpha = 1.0f, this can be seen in figure 18. Unfortunately this gave some nasty side effects which are discussed in the Triangle Blending Artifacts section, in the Problems chapter. 1 0 0 = 0
Figure 18: Blending algorithm example In this example it is assumed that the bottom layer (what is already there) is dirt and that we have currently selected a grass TiledTexture that we want to apply to some tiles. The top part of the figure is the same as the TileGraphic template described in figure 11. The bottom-left of the figure shows the alpha values for the vertices of the tile corresponding to the values determined in the template (above). The bottom-right of the image shows the result of the operation. (The theoretical result, the real result might differ, for more information refer to the Triangle Blending Artifacts section.)

V0, a = 1

V3, a = 0

V1, a = 0

V2, a = 0

26

Tile Structure Problems (second version)


Although the paper version of the second method used for the tile structure looks much simpler than that of the first version, the second version was much harder to implement and cause much more problems. In this section I will discuss only a few of these problems as there is no space for dealing with them all. (For comparison, to get the first version (of tiling) to work flawlessly cost me about a week. To get the second version (of tiling) to work flawlessly took me about four weeks. (Note that these weeks are not 40 hour working weeks.) This was mainly because the second version depends heavily on what has been rendered already, the second version of the Tile structure took too much memory which needed to be optimized, which in turn made the tile placement algorithm cryptic (to stay polite) to deal with.) Never the less I finally got a very nice result which is in my eyes better than the Command & Conquer Generals results, for I do not have to focus on which tiles to blend manually (which you have to do with that editor) and I do not suffer from the three way blend error as it does (see figure 19).
Figure 19: Three way blend error This figure shows the three way blend error as they appear in the Command & Conquer Generals worldeditor. The three way blend error occurs where three different tile textures are blended together. I fortunately do not have this type of error anymore, but then again I do not have the same optimization they used (probably some three texture units in a single rendering pass).

Too many textures


Although the version 2 method of texturing the tiles does not require a TileGraphicSet and can therefore use any texture that is available this poses a problem for the texture memory of the video card. Suppose you have a large texture library that contains around 500 MB of textures, it is not hard to see that although you can use all these in a single (large) level it kills the rendering performance because a lot of texture data has to be streamed from system memory to video card memory (until video cards with more than 500 MB of memory becomes the standard). Since this really is the problem of the terrain

27

editor I will not go deeper into this subject. It would be nice to make some function that calculates the currently occupied memory for the textures on a terrain. (Note that such functionality is not directly present in the current version of the code, but with a slight modification to that code it can be added easily because the Texture class already has a CalculateUsedMemory() method.)

Color Blending Artifacts


This section describes the color blending artifacts problems I encountered while trying to implement the textures so that they blend between neighboring tiles, see figure 20.

Figure 20: Color blending artifacts The left side show what is required, the right side shows what blending artifacts caused. Notice that the luminosity of the right image is too bright for the blended tiles.

In figure 20 the left side of the figure displays the image as it should have been. The right side of the figure displays the image that resulted from using multi-pass rendering using the glBlend(...) function. The artifacts occur because the glBlend(...) function takes the current pixel color in the render buffer into consideration and blends this with the color of the current texture. Normally we render the tiles with code like:
glTexCoord2f(...); glNormal3f(...); glColor4f(...); glVertex3f(...);

But because the alpha blended tiles need the alpha component for each vertex, we need code like:
glTexCoord2f(...); glColor4f(..., vertex_alpha); glVertex3f(...);

28

The call to the glColor4f(...) function disables the OpenGL lighting calculations so that a call to the glNormal3fv(...) function does not serve any purpose. This problem was solved by calculating the color components for the vertices manually (the dot product of the light s direction with the vertex s normal yields the cosines value for the angle between the light and the normal, which in turn defines the color intensity for the vertex.) Another benefit of calculating the vertex colors by hand is that at rendering time OpenGL does not need to be concerned of the lighting calculations for the terrain. A minor disadvantage resulting from this method is that we now need to recalculate the colors our self when the material of the terrain changed.

Triangle Blending Artifacts


I encountered some blending artifacts that arose due to the way OpenGL renders quads. Video cards actually only support rendering triangles and rendering a quad is therefore split into two triangles. The way this split is made depends on the order in which you specify the vertices, also see figure 21.
V0 V3 V3 V2

Figure 21: Quad to triangle This figure shows how OpenGL triangulates the quads given the vertices v0, v1, v2 and v3. Note that the order in which the vertices are passed is v0, v1, v2 and v3. The left part of the figure shows two triangles in a / layout and the right part of the figure shows two triangles in a \ layout.

V1

V2

V0

V1

Because the Gouraud shading interpolates the vertices on a per triangle basis this yields some strange blending artifacts, also see figure 22.

Figure 22: Gouraud shading This figure shows how Gouraud shading interpolates on a per triangle basis. The left part of the figure shows two triangles in a / layout and the right part of the figure shows two triangles in a \ layout. Note that the left part of the figure looks more correct, but thatis just because these colors tend to blend in that fashion, it can look just as wrong as the right side does now (given the wrong colors).

This blending in combination with the TileGraphic templates (figure 11) made the blending look squared for some tiles, also see figure 23. To deal with this problem I

29

added a property to the tiles indicating in which order the vertices should be given to OpenGL. There is a slight side effect by doing that however. Since the vertices differ in elevation rendering a /triangle layout uses different elevation values on the edges of the triangles than a \triangle layout. The only way to overcome this is to render all layers of the tile with the same triangle layout, which in turn messes up the blending. Nevertheless this method proved useful because I set the tile s triangle layout based on the TileGraphic layout of the top most layer, since that is the layer you see most of. This only leaves us with visually disturbing cases sparsely and a placing the textures cleverly eliminates them all. This is beyond the scope of this document as it is the terrain designer s task.

Figure 23: Triangle Blending Artifacts This figure shows the triangle blending artifacts that occur because of Gouraud shading in combination with the TileGraphic template structure (figure 11). To show the differences clearly the wrong blend uses a red texture and the right blend uses a green texture, the effect is the same for normal textures such as dirt, grass etc. The top part of the figure uses a / triangle layout for all the tiles. The bottom part of the figure uses a / triangle layout for the top-left and bottom-right corners (since these were correct already). It uses a \ triangle layout for the bottom-left and top-right corners which blend correctly now.

Tile Blending Artifacts


Next to the Triangle Blending Artifacts I also suffered from tile blending artifacts. Tile blending artifacts are a consequence of the layering system. If you look at figure 11 you will see cells filled with binary numbers. These numbers indicate the alpha value for each edge, as you already know. These alpha edges are however also required to be unique (due to some implementation issues, see the TileTerrain HTML documentation and code on the CD for more information). This means that if layer one has an alpha value of 1 for vertex 0 then neither layer 2, 3 and 4 can have an alpha value of 1 for vertex 0. Unfortunately it is possible (when using multiple layers) to have a combination of blends that do not occupy the whole tile, which causes the layers above the layer with the alpha set to 1 for the specified vertex to blend with the bottom layer instead of the layer directly below it. Because this is quite hard to understand I will give two large figures with a

30

detailed explanation: figure 24 and figure 25. To achieve the correct blend and still keep each vertex alpha unique, as required by the algorithm, I do the following: Traverse all layers from top to bottom and every vertex with alpha 1 will also have alpha 1 for all vertices in the layers beneath. This invalidates the uniqueness property and I run the inverse algorithm before running the algorithm that calculates the correct vertex alpha.

31

Base layer

1 1 0 2 3 0

1 1 2 0 0 0

Blending =

Layer 1

Blending =

Layer 2

Blending =

Figure 24: Tile Blending Artifact (wrong blend) The top 3 strips indicate the layers we currently have: base layer, layer 1 and layer 2. The base layer is filled with grass, layer 1 has a / shape of sand and layer 2 had the top-left part of the tile of dirt. The corresponding TileGraphic templates are indicated by the bit fields. The middle-left part of the figure indicates what happens when the base layer is blended with the layer 1 layer. The sand of layer 1 is blended with the grass correctly. The middle-right part of the figure indicates what happens if the result of the previous blend is blended with the layer 2 layer. The dirt of layer 2 is blended with the result of the previous blend operation which blends which is the grass since the previous layer did not fully overlay the grass layer on that corner. This is considered a wrong blend because you get strips of sand with edges of dirt. The lower part of the image demonstrates the full effect of this wrong blending, which is visually disturbing.

32

Base layer

1 1 2 2 3 0

1 1 2 0 0 0

Blending =

Layer 1

Blending =

Layer 2

Blending =

Figure 25: Tile Blending Artifact (correct blend) The top 3 strips are the same as described in figure 24. The middle-left part of the figure indicates what happens when the base layer is blended with the layer 1 layer. The sand of layer 1 is blended with the grass correctly. The middle-right part of the figure indicates what happens if the result of the previous blend is blended with the layer 2 layer. The dirt of layer 2 is blended with the result of the previous blend operation which is correct now. The lower part of the image demonstrates the full effect of this correct blending. It is much harder to see the transition edges using the correct blending method.

33

Tile Storage
My first implementation of the Blended Tiles concept (version 2) used a tile structure of 168 bytes:
class TiledTexture; struct TileTextureRectangle { TiledTexture *texture; float l, t, r, b; }; struct TileAlphaRectangle { float a0, a1, a2, a3; }; struct Tile { Tile() : texture_count(0) { } unsigned int TileTextureRectangle TileAlphaRectangle }; texture_count; texture_rectangle[5]; alpha_rectangle[4];

Each tile has a maximum of 5 layers, 5 texture layers of which the upper 4 are blended tiles. On it self 168 bytes does not seem that bad, but consider a terrain of 256x256 tiles, that are 65536 tiles each 168 bytes totaling almost 11 MB of tile data. Or even worse, consider a 1024x1024 terrain totaling 168 MB of tile data. This is an unacceptable amount of memory for something that simple, so optimization was required. It was soon clear that since the alpha for each vertex could only be 0 or 1 this could be optimized using bit fields. Another thing that sprung in mind is that pointers each require 32 bits (4 bytes), but I was planning on using at most 256 different textures for the terrain. To keep future extensions in mind I made it possible to use 1024 different textures for the terrain by using a bit field of 10 bits per texture. Further, since the number of layers is at most 5 a 3 bit bit field suffices for the layer count. The last and most saving optimization was that of the texture coordinates. In the old code I saved the texture coordinates in the tile structure, but I could just store the texture alone, since the TiledTexture coordinates are directly derived from this tile (using the relative offset in the world). After this reordering the Tile structure has the following shape:

34

struct Tile { ... ... ... // 32 bits block unsigned int unsigned int unsigned int unsigned int unsigned int

tex0 tex1 tex2 a1_v0 a1_v1

: 10; : 10; : 10; : 1; : 1;

// 32 bits block unsigned int unsigned int unsigned int unsigned int unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned int int int int int int int int

tex3 tex4 a1_v2 a1_v3 a2_v0 a2_v1 a2_v2 a2_v3 a3_v0 a3_v1 a3_v2 a3_v3 a4_v0 a4_v1

: 10; : 10; : 1; : 1; : : : : : : : : 1; 1; 1; 1; 1; 1; 1; 1;

unsigned int unsigned int

: 1; : 1;

// 32 bits block unsigned int unsigned int unsigned int unsigned int };

a4_v2 a4_v3 layers reserved

: 1; : 1; : 3; // range [1..5] : 27; // reserved for future use

(For a full listing of this structure see the Tile.hpp file) This structure takes only 12 bytes instead of the 168 bytes previously. The main disadvantage with the new structure is that the algorithm for calculating which layer uses which texture, which layers should be removed, etc, cannot access the structure components easily. Therefore I made some access functions that make this a little bit less hard. Never the less the layer calculation algorithm code has really dramatically increased in complexity.

35

Rendering speed
Because I use efficient storage of the tiles (to conserve memory) I had to extract per tile information for each rendered tile. This resulted in 54 fps, which is unacceptable. Batching vertex data would be beneficial. Recalculating the visible mesh data every time the camera moved (in cluster based fashion) improved the frame rate by a factor of almost 10, yielding far above the 500 fps. The Recalculation of the visible mesh data is a task that has to be performed fast and because of that you cannot free and reallocate all the memory every time you do it. The most obvious reason for this is that it is very hard to predict the amount of memory needed for each frame and the calculation is quite costly as well. To resolve this problem I created a template GrowArray class of which the main purpose is to store data in array form and be able to clear the array without actually releasig the memory. The GrowArray class has an append method for appending data to the array (internally new memory is allocated for the current amount + N, where N is the specified grow size for the class, components larger than it was. Data is copied and old memory released). This whole process is transparent to the programmer. The benefit of this approach is that you will have approximately the memory required for storing the components (your are not reserving way to much memory). The bad side of the algorithm is that if there is a big leap in the amount of vertex components to store, the GrowArray will perform multiple reallocations and copies of memory. Fortunately this seldom happens and the accompanied performance loss is for a single frame only. Using indices to avoid even more duplicate vertex data is not an option since using indices requires the index to point into every array (vertex, color, texture coordinates, etc). In my case only the texture coordinates changed for the alpha blended tiles, but it still required me to duplicate the blended color values at least and the position data because the layers are do not have same set of tiles. To further improve the rendering speed, I batched consecutive tiles that share the same texture. This saves a lot of texture state changes in the OpenGL implementation which improves performance. Note that I only batch consecutive tiles not all the tiles in the cluster. Although performance could be increased even more if I batch all tiles in the cluster by texture handle, this would put more strain on the recalculation of the visible mesh data. Because this is a world editor the mesh data is changing rapidly and the extra time spent on this optimized batching will result in frame rate drops below the limit of what is acceptable. This does not mean that this method is impossible at all. One could consider such an optimized batch organization for the final terrain, in other words the terrains that ship with the game. This is possible because in that situation the batched data will just be pre-calculated and stored in the terrain file on the disk. This is not part of this assignment, because I did not make a game, and therefore I will not go deeper into this matter.

36

One last optimization I implemented is the use of texture compression for the video cards that support it. Texture compression reduces the size of the textures in the video memory and therefore less texture data transfers from system memory to video card memory have to be made. This optimization also causes the image quality to be decreased a bit, but since it is not really visible I left it that way. (except for the shadow maps, see the Texture Compression section in the Problems chapter for more information on that subject). Note that there might be a better way of rendering using some of the various extensions that are available, but this was not the goal of my rendering algorithm at the time of creation. Multi texturing for example will improve the rendering speed even more, but at this time that has not been implemented yet. The use of triangle strips could also improve the rendering speed due to less data sent to the video card.

37

Visibility processing (both versions)


This chapter deals with how the visibility processing for the terrain is implemented. Because the amount of polygons that make up the terrain is quite large and the visible part of the terrain is often quite small, we need some way to determine which polygons are visible quickly.

2D (Normal) Quad-tree
A Quad-tree is a 2D recursive subdivision method that divides a rectangle into 4 sub rectangles when a division is required. In the TileTerrain engine the sub division is repeated until a defined cluster size is met. The cluster is in the final version of the terrain is 4, which means that each leaf of the quad-tree has 4x4 = 16 tiles. This cluster size was determined after extensive performance testing. The cluster size speeds up the rendering because rendering 16 tiles is quicker than traversing the nodes of the quad tree a few steps further. (Note that this might differ per video card.)

Figure 26: 3 Level Quad-tree subdivision. The left part of the figure is the first level of sub division (the root). The middle part of the figure is the second level of sub division; the green lines indicate the children s node limits based on the root node. The right part of the figure is the third level of sub division; the blue lines indicate the children s node limits based on the second level.

3D Quad-tree
I use a blend of the normal Quad-tree in the following sense. I use a Quad-tree for virtually dividing the terrain. Note virtually because I do not actually use the terrain s vertex data for this process. The 3D part comes from the fact that I give each Quad-tree node a minimum and maximum elevation value (which are equal to the global minimum and maximum of the terrain) for every visibility / ray-intersecting operations. Testing the Quad-tree only occurs when the camera moves and when the mouse moves over the terrain. This gives high frame rates when the screen is not scrolled, but the frame rate drops a bit when moving the camera.

38

Lighting the terrain


Although the tiles are textured and the textures might be used to indicate elevation (for example, low grounds dirt, a bit higher grass, , mountains with rock, mountain tops with snow, etc), this still does not make the terrain look right. In order to let the terrain look more sophisticated, the terrain will require two types of lighting: per-vertex-lighting (both versions) and light / shadow mapping (second version).

Per-Vertex-Lighting (both versions)


Per vertex lighting calculates the light intensity at each vertex of the terrain mesh data and interpolates this over the quads. The results of this can be seen in Figure 27.
Figure 27: Per vertex lighting The light in this figure comes from the bottom-left corner. All sides of the hills that point to in that direction are more lit up than the sides of the hill that point away from the light. This effect gives the terrain more depth. Note: This is a very unrealistic terrain, but it shows what I want to show very clearly. Also note that the light that is falling on the terrain is quite yellow, giving the impression that it is a summer afternoon.

A nice feature that can be implemented easily using per vertex lighting is that you can change the color of the light, or the direction of it, that shines upon the vertices (not implemented in the terrain editor, but it is adjustable in the code). When this technique is used appropriately the effect of different light intensities that are encountered on a day (for example: dusk, noon, evening, dawn, etc.) can be simulated. Per vertex lighting had some problems associated with the blending of the tiles, for more information see the Tile Structure Problems (second version) chapter in the Color Blending Artifacts section.

The implementation of Per-vertex-lighting


Because the blending of the tiles required both the exact RGB color value of the vertex and the alpha value (see the Tile Structure Problems (version 2) chapter in the Color Blending Artifacts section), I needed to calculate the vertex colors by hand. Fortunately the calculation for a directional light is easy and fast. One big benefit was that I had the NormalGrid class already and therefore the per-vertex normal vectors were already calculated for me.

39

The directional lighting formula I used for lighting the vertices uses both ambient and diffuse color. Ambient light is the base intensity that the vertex always receives. For the diffuse component of the directional light only the angle of the incoming light is needed for each vertex. Since the intensity of the directional light is equivalent to the cosine of the angle between the incoming light and the normal for the surface at the incoming light point. The angle between the two vectors is easily determined by the formulae: cos angle = (V dot W) / (|V| |W|). The |V||W| calculation is relatively slow, because it requires two square roots and seven multiplications. Fortunately the |V||W| calculation can be ignored in the case that both the V and W vector are normalized vectors, which I enforced. The resulting angle then becomes the following formulae: cos angle = V dot W. The total light calculation I used therefore is: Vertex-Color = Ambient-Color Intensity = DotProduct(LightDirection, SurfaceNormal) Local-Diffuse-Color = Diffuse-Color * Intensity Vertex-Color += Local-Diffuse-Color After this calculation the Vertex-Color is clamped to fall in the [0.0f, 1.0f] range, to assure normal visual results (specifying colors larger than 1.0f create a scene wash out).

Shadow Mapping (version 2)


Shadow mapping does basically what its name says: it casts shadows over the terrain where required. The results of this can be seen in Figure 28.
Figure 28: Shadow mapping The light in this figure is the same as that in figure 27. The shadow casting can be clearly seen in the lower/middle part of the image. The shadow is casted from the spiky hill in the lower part of the image. The reader that looks carefully at the image sees that every hill casts a shadow and that the further the shadow is removed from the hill that casts it, the less solid the shadow gets. The shadow mapping effect is so common to people, that you really will not notice it until it is missing (see Figure 27).

40

The implementation of Shadow mapping


Conventional shadow-mapping algorithms tend to be based on ray-trace algorithms that check intersection of the light ray in reversed order. I built a basic ray-tracers for this purpose but it turned out to be useless for my purposes (see the Shadow Mapping Problems (version 2) chapter in the section Ray-Tracer problems). After trying the ray-tracer method I thought up of my own way to perform the calculations and found something. My implementation of shadow-mapping is actually quite simple, but very effective for terrain engines. I will explain the algorithm step-bystep: Interpolated elevation grid generation Shadow image generation Shadow image post processing Shadow image to Shadow map conversion The final result

Interpolated elevation grid generation The first step in the shadow-mapping algorithm is to calculate an interpolated elevation grid, where the resolution of that grid is N times larger than that of the original elevation grid. The N is determined by the number of lumels per tile. There are two possible ways of interpolating the original elevation grid: Physical interpolation (based on the tile s triangles) Logical interpolation

The physical interpolation is based on the layout of the triangles in the tile. The most important property of this approach is that it tends to follow the terrain closely. Although that property is desired to move units around on the terrain, it is not desired for creating the shadow image because that would clearly show the triangular shape of the terrain mesh in the shadow image, which is visually disturbing. The logical interpolation is based on a bi-linear interpolation between the vertices that affect the elevation. This interpolation is in essence the same as the bi-linear color interpolation used in rendering known as Gouraud shading. This does not follow the terrain closely but interpolates the elevation making the transitions smoother, therefore this method is chosen. Note that logical interpolation can also be used to let the camera follow the terrain, since it provides a smooth interpolation into all directions to the neighboring tiles (not implemented).

41

Shadow image generation The second step in the shadow mapping algorithm is the generation of the shadow image itself.

(0,0

(1,0)

(2,0)

For every elevation value in the interpolated elevation grid the algorithm starts moving in (0,1) (1,1) (2,1) the minus x direction and in the positive y direction (as shown in figure 29). Then the algorithm checks whether the elevation value of that cell is higher than the original elevation plus the elevation that the light s Figure 29: Shadow Image generation ray ray adds over that distance. In the mean while the ray s distance is maintained to The thick black lines represent the tile produce shadows that are less opaque when borders and the small squares represent the they are further away from the intersection interpolated elevation grid values. The red line represents the direction of the ray. Each point. To give the algorithm a bit more interpolated elevation grid that is intersected speed the rest of the ray is ignore when the by the ray is tested to determine whether the currently tested elevation is greater than the light can reach the ray s origin. global maximum (in which case no more intersections can occur) or when the x and / or y coordinates are smaller / greater than their minimum / maximum. To make the results of the algorithm less harsh we test for at least N intersections before making it a shadow lumel. After experimenting with the shadowing algorithm I found out that it visually pleasing to make the shadows that are further away from their creation point less opaque, see figure 30.

Figure 30: Less opaque shadows based on intersection distance On the left side you see the terrain lit with the raw, without post processing, shadow image. The hard shadow edges are very apparent in the centre of the image. The image on the right is the shadow image itself. (Note that the image on the right might look the same as the terrain, but the terrain has actual elevation. The shadow image is applied to the terrain on a per polygon basis. So the image is not rendered over the terrain as a flat quad).

42

Shadow image post processing After the shadow image has been generated, there is some post image processing to enhance the visual quality of the shadow image. In my situation the post image processing consists out of applying a cubic blurring / smoothing filter. The filter determines for every pixel the pixel s color based on the color of it self and all surrounding pixels (The number of pixels added is 4 for the corners, 6 for the edges and 9 for the centre pixels). A single blur / smooth pass is not good enough for eliminating the hard edges, so multiple passed were done. Too many passes wash out the shadow image too much and take too much time. Therefore I experimented with different settings and found out that a value of 4 is sufficient, see figure 31 for more information. (Note that this amount is configurable at compile time by setting a #define directive in the Defines.hpp file).

Figure 31: Shadow image blur / smooth passes From left to right, the shadow image with respectively: 1, 4 and 8 times the blur / smooth filter applied.

Shadow image to shadow map conversion. The final step in the shadow map creation is to convert the shadow image to (multiple) shadow maps. The shadow image can be any dimension, but the rendering hardware requires a texture with dimensions that are powers of 2 and limited in size. These are not the only factors to take into consideration. Another very important thing is the amount of memory the shadow map uses. For example, a terrain of 256x256 with 4 lumels per tile requires a 1024x1024 shadow image. On most recent hardware, this texture size is supported so there actually is not a problem. The thing to keep into consideration however is that most of the time you only see a small portion of the landscape and hence see the shadow images for those portions only. Therefore keeping a texture with large dimension in the video card s texture memory is a waste of that memory (Note that a shadow image takes 3 color components and therefore a single 1024x1024 texture uses 3 MB of texture memory). Therefore I split the shadow images into smaller textures. Unfortunately I could not make the shadow map textures fitting to the cluster size, since the cluster size is 4 tiles which is just too small because together with the 4 lumels per tile, this would create textures of 16x16 texels. On itself this is possible, but not very efficient because every texture object stores some internal information. In the example

43

that is used in this section, the terrain is 32x32 tiles with 4x4 lumels per tile and a shadow texture size of 64x64. The shadow image that is created is 128x128 (32x4 in both dimensions) and therefore there will be 4 shadow textures generated, see figure 32.

Figure 32: Splitting the shadow image into four shadow maps. The left part of the figure shows the shadow image as a whole. The right part of the image shows how the image will be subdivided to generate the shadow map textures.

A problem with this approach is that the edges of the shadow textures are repeated. This results in large dark lines at the edges of the shadow textures. According to the OpenGL specification this is simply solved by adding a border to the texture image. Experimentation with this feature unfortunately pointed out that the border functionality is not supported by much recent hardware. (Most of the consumer level 3D cards has no hardware support for texture borders, Quoted from www.opengl.org, topic posted by Serge K.) Basically there are two solutions to this problem that tend to work: 1) manipulating the texture coordinates Figure 33: Black texture border artifacts manually so that the texture does not blend The black lines from the top to bottom and from with the border color, and 2) using the the left to right in the centre of the image are the GL_EXT_texture_edge_clamp extension result of an OpenGL texture blending artifact. to fix it. The first method is tedious because you have to adjust the code. The second method works perfectly, but only OpenGL specification 1.2.1 and above support it. According to the required system specifications (see the appendix A: System Specifications) the program requires at least a GeForce-II MX or better, these cards support this extension, and therefore this method is used.

44

The final result After all these steps the shadow map is generated quickly and precisely with less opaque shadows that are further removed from the geometry that created the shadow, see figure 34 for the result.

Figure 34: The final shadow mapped result.

45

Shadow Mapping problems (version 2)


Ray-tracer problems
While writing my shadow map generator for the terrain I encountered several severe problems. I will elaborate on the two major problems only, since dealing with the other problems will take up too much space. The first of this problem was that a brute force approach was too slow. To create the shadow maps I generated for each tile a 4x4 or 8x8 grid of lumels on the fly (by using logical interpolation).
Figure 35: Tile Lumel grid

(0,0)

(1,0)

(2,0)

(0,1)

(1,1)

(2,1)

The thick black lines represent the tile borders. The green colored grid is the tile lumel grid for the tile (0, 0). The small cells represent the lumel coordinates generated on the fly (note that in contrary to figure 29 the small cells are not values in the interpolated elevation grid, since the ray-tracer method does not require that).

For each of these lumels a 3D location on the terrain was calculated and then a ray from this point in the direction of where the light was coming was generated (The length of the ray large enough to span the terrain.) The brute force approach was to test every ray against every triangle of the terrain. This might not seem a very bad idea in the first place, since the amount of triangles for an average terrain is not that bad. Suppose an average terrain is 128x128 tiles, then each tile contains 2 triangles, which gives a total of 32768 triangles. The problem resides in the fact that for each of the lumels in the tile you need to test for an intersection between any of these polygons. If we go to the extreme and take an 256x256 terrain with an 8x8 lumels per tile grid this would require a lot of calculations: 256x256 = 65536 tiles = 131072 triangles with totally 256x256x8x8 = 4194304 lumels to calculate. This implies 4194304x131072 ~ 5.5*1011 calculations. For ease of calculations let us assume that each test costs 1*10-6 (one millionth of a) second then the total calculation of the shadow map would cost approximately 6 days. Clearly the brute force method did not suffice. I optimized the algorithm by first testing the ray against the 3D Quad-tree structure. The 3D Quad-tree has an axis aligned subdivision and each node can therefore be encapsulated by an axis aligned bounding box. The ray intersection for an axis aligned bounding box is quite fast and because the Quad-tree subdivides the terrain recursively we are quickly discarding polygons that cannot possibly intersect the ray. To illustrate this idea see figure 36 on the following page.

46

Figure 36: Ray AABB intersections A) first level B) second level Assumed is a Quad-tree with 3 levels, which implies a 16x16 grid (each cluster is 4x4 tiles). AABB = Axis Aligned Bounding Box A) The ray is tested against the AABB of the first level of the Quad-tree, it intersects so we proceed to the next level. B) The second level of the Quad-tree is tested against the ray, only the top-left, top-right and bottom-left Quad-tree nodes intersect with the ray, so these are expanded. C) The third and final level of the tree, the same procedure is repeated. D) The actual intersections found are colored yellow. This means we do not need to test the ray intersections for all polygons in the white areas.

C) third level

D) actual intersections

Another optimization I used was to check the maximum elevation per tile against the minimum elevation for the currently checked tile. It is easy to see that if the maximum value of a tile is less than the minimum value of the current tile it is impossible for the light ray (which never goes underground) to hit it. These optimizations were able to generate a shadow map for a 32x32 tiles terrain using an 8x8 lumel grid per tile in approximately 8 or 9 seconds. This speed increase is quite big, but it is not enough for the future. For example: generating the shadow map for a 256x256 tiles terrain using a 8x8 lumel grid would take approximately 10 minutes at this speed. This is unacceptable, especially when one realizes that I was planning on implementing dynamic terrain shadow maps (based on the position of the sun). For this moment we will leave this speed problem aside however and continue with the next problem. The second problem is that the generation of the shadow map sometimes introduced holes in the shadow map. Also the cutoff of the shadows (on the lower part) seemed unrealistic, see figure 37.

47

Figure 37: Shadow map holes It is clear that the shadow map has some holes in it. Also the cutoff of the shadow on the hill tops seems unrealistic. Note that in the image the shadows are blue, this was not the final result, but it is displayed in this way to have more contrast in the image.

Although I am not completely sure about the origins of these holes I have an explanation which is most likely the cause: point in convex polygon testing. The method I used for testing whether a ray is intersecting a polygon consists out of 2 parts. The first part determines whether a ray is intersecting with a plane and yields the intersection point (which cannot go wrong). The second part determines whether the intersection point calculated in the first part is inside the convex polygon. The method I used to determine this is to calculate the angles between the intersection point and all the vertices. If the sum of these angles equals 360 degrees the point is inside the polygon, otherwise it is not. A problem with this method is however that points lying on the edge of the polygon or on a vertex of the polygon might sometimes be seen as outside the polygon. There is another approach to determine whether the ray is inside the polygon or not: for each edge of the polygon, build a plane (using the normal vector of the polygon) and test the point against this plane. This method will never yield outside results while it is actually inside (though the opposite might occur depending on the virtual thickness of the plane, this effect is less disturbing however.) A serious problem with this method is however that this type of checking takes a lot more time than the summed-angle approach. And since the speed of the shadow generation algorithm was already unacceptable I did not try this approach further.

48

Generic Problems
This chapter lists the generic problems that I have not discussed yet and they are not specifically related to either version of the TileTerrain. Note that only the two most disturbing problems are treated since there is no space left.

Brushes
The first implementation of the brushes had an array of apply-factors for each brush object. This array was 32x32 in size and its elements were floats (each 4 bytes large). This implied that each brush object was around 32x32x4 = 4096 bytes large. While updating the terrain editor so that it supports macro-commands this gave some memory problems. The macro-commands allow multiple applications of a brush object in a single command. (A mouse-apply-start starts the command, the movement of the mouse keeps applying the brush and finally a mouse-apply-end ends the command.) Because each subcommand of a macro-command requires a brush object this consumes memory fast. Therefore a memory optimization of the brush class was required. The optimized version of the brush does not have an array that holds the apply-factors. Instead the brush s values are calculated on the fly. This severely reduced the brush size solving the memory problem.

Texture Loading
Normal texture loading does not take much time, unless you create mipmaps for the texture. The problem with mipmapping is that you have to scale the image down till a resolution of 1x1 is reached (note that this is not mandatory using some extensions, but I will ignore that for the sake of simplicity). More loading time is added because I implemented some features that enable flexibility of rendering hardware. These features are all calculated while loading the texture and include things like: changing the resolution of the texture, changing the color depth of the texture, forcing texture wrapping modes, etc. Changing the resolution of the texture on the fly is especially expensive. Both mipmapping and changing the resolution of the texture are slow because they scale the images using the (quite generic) gluScaleImage function. So how slow is slow? For example: loading a 24-bit texture of 512x512 costs more than 600 milliseconds on my machine. It is not hard to see that loading a full terrain with about 128 textures takes way too much time in this fashion. A solution for this problem is to write a more specific, hence faster image scale function. This can reduce the texture loading quite a bit, but another, better solution for this problem lies in writing a loader for the .DDS mipmapped texture file format. (http://developer.nvidia.com/object/nv_texture_tools.html) This format stores the lower resolution images in a file so that the scaling operation is performed only in preprocessing time. Unfortunately I did not have time to implement this in my texture class. 49

Texture Compression
To save texture memory I have used texture compression on video cards that support it. However compression unfortunately causes some artifacts on the shadow-map however that is really disturbing, see the image on the left (Note that the problem is exaggerated because I use almost totally white textures).

Figure 38: Texture compression in shadow map causes artifacts

These artifacts arise due to the nature of texture compression for which every 4x4 block of pixels is encoded using 8 bytes (no alpha). (GL_COMPRESSED_RGB _S3TC_DXT1_EXT). In combination with the already low resolution (4 lumes per tile) of the shadow map this generates a lot of interference. Because of this I disabled the texture compression for the lightmaps (only) in the final terrain editor version, the result can be seen in the image on the right.

Figure 39: No texture compression in the shadow map.

Note that texture compression still is enabled for the textures them selves as this is hardly noticeable.

50

Features that did not make it


Meshes
I wanted to be able to put some meshes on the terrain in order to make the terrain a bit livelier and to show how one could use the engine to create a game based terrain by creating meshes and adding them to the terrain. Unfortunately this has not been finished completely. The code to do it is basically there, but I did not have enough time to integrate it all into the level editor.

Figure 40: Some meshes I made (Part 1) Top Left: Old Ford out of the year 1946 (238 polygons), simply created by applying a colorize filter on parts of the original texture (see figure 41) and applying that texture to the same mesh. This technique can be used to speed up the development of meshes without breaking the uniformity of the meshes in general. One could slightly modify the original mesh as well to prevent the feeling that the meshes are all the same. Top Right: M1A2 Abrahams (untextured, 389 polygons) tank

Left: Water Tower (241 polygons) first model that uses a texture with an alpha channel to block out parts of the mesh (mainly the X construction that are attached to the pillars and the ladder)

51

Figure 41: Some meshes I made (Part 2) Left: Top Right: Bottom Right: Lighthouse, this lighthouse has a rotating top with a light beam attached to it that rotates as well. (288 polygons) Old Ford out of the year 1946 (238 polygons) Wooden Cabin (110 polygons)

52

Water
I implemented some basic animated water. The animation is a mesh based animation for which the data is pre calculated according to some configurable parameters: wave amplitude (per tile), mesh density (overall) and speed of water animation. Unfortunately my water implementation was not visually attractive. Although the mesh is deformed, this is hardly visible because you never see the water mesh from the side (which is the only position that would allow you to see the actual mesh deformation). The mesh also tends to take up quite a lot of rendering time (depending on the density of the water mesh). Another disturbing feature is that the tiling character of the water is clearly visible. The final problem with my water implementation is that the edges where the water touches the solid terrain are really hard (also see the image below). There is a really nice thing about this water however. The water gets darker blue as the water gets deeper, which is comparable to real life water. A better implementation would have been to apply an animated texture onto a planar surface. To remove the hard edges I would have to set alpha for the vertices that lay inside the terrain to zero make the transition invisible. Note: If you want to see the water in action in real-time, check the Applications/Water directory on the CDROM.

Figure 42: Water, see the demo application.

53

Conclusion / Evaluation
This chapter deals with the conclusion and evaluation of my work as I see it. It is divided into four sections: the code, theory, overall and result sections.

Code
The first thing I noticed, but I always have that with projects, is that I should better decide before coding what I want and how it works, write down the dependencies etc, then make a design for that and then start implementing. Like I said, I always have that with projects and it is most likely to happen every time I do something new, something I have never done before. I think that a person just can not think of the right abstractions before he had some experiences in the corresponding field of work. I guess that is just the difference between beginners (me) and experts, they tend to make the right decisions the first time just because they experienced something with past projects. Secondly I noticed that the code is highly cohesive, a large part of the objects are interconnected intensively resulting in a lot of calls just forwarding code. I think that although university tells us to use an object oriented approach (as we are taught by using Java) one should see this in the correct light. My purely object oriented approach for example tends to be a bit too object oriented for its purpose. Afterwards I feel that it would have been better if I programmed the TileTerrain component as a set of (on the level of the TileTerrain component) global variables that are manipulated by a class that is exported to the programmer that uses the Terrain, like a sort of a wrapper class. After the project I studied some professional project source code (for example Quake 2, Half Life 2, Doom II, Abuse and the Fly3D SDK) and I found that such an approach is indeed more manageable with less function forwarding and less object tangling. Such an approach would have saved me the thick pasta layer I currently have. Another annoying thing with the object oriented programming style I used is that I have a lot of data hiding (which people make you believe is good) and I prefixed these private data members with an m_ since that is the Microsoft way. That turned out to be a big mistake. Every time I had to move a data member from private to public (to increase the speed of the code for example) I had to find / replace all the instances. This sometimes had the nasty side effect that the code broke due to a method parameter then having the same name as the data member which would give something like filename = filename instead of m_filename = filename. What really annoyed me was that the method documentation with the Doxygen comment style was obstructing my visual overview of the code. I just could not see all the functions in one view anymore since there were multiple lines of comment in my way. Now do not get me wrong and think that I would like to do without the documentation, I do not, but I think that I should have placed the major part of the documentation way later in the project. Because while I was working I knew what every function did, the documentation actually is only for other programmers and for later reference. I managed anyway by using the nice text hiding system Microsoft Visual Studio .NET offers though. 54

Theory
What really amazed me is that stuff I though to be really simple to implement or fix, actually turned out really hard. Take the shadow-map generation for example. The theory behind this technique is really simple, just shoot a ray from the lumel you have to the light source and if it hits a polygon you do not receive light from that source. In practice however, there are major difficulties related to this ranging from purely implementation wise to side affects created by the application of the shadow image. Implementation difficulties are for example: speed of the algorithm, preciseness of the algorithm, etc. (This has been discussed elaborately in the Shadows section) But there are other really difficult things that happen when you apply the shadow image: Since the color grid already indicates color, an application of the shadow image would result in double blackness of the shadows for the parts of the terrain mesh where the mesh is also affected by the color of the vertices. This is difficult to solve because when you turn off the colorper-vertex data, you do not receive any shadow coloring for the parts that are facing away from the light but do not result in a ray intersection. That kind of stuff is hard to detect on paper. The theory behind caching vertex data is also really easy, but as it turns out you have to fill the cache buffers with data of which you do not know the size yet, you should perform some optimization that batches the primitives, etc and still keep it fast enough so that the user does not notice anything. All in all this turns out to be really simple on paper, but in practice a bit harder. Also theoretical algorithms are perfect in precision and speed, but as it turns out implementing them is a world of its own.

General
During the course of the project I ran into numerous problems ranging from bad design, machine limitations (memory wise, render speed wise, etc), unsatisfying results (mainly the first tiling system) and just too much hacked code to be able to work with. I think that in the end getting the stuff to render at high speed was the most difficult task I faced. The most difficult part of the code is the part that makes the rendering efficient with all the tiling code etc. For example: I can write a brute force Tiling system like that of version 1 within 6 hours (I did), but as soon as optimization kicks in you are in for a total recode or two. Also, when all the visibility stuff gets in it is harder to find errors and fix them.

55

Results
In the end the result is in my eyes somewhat disappointing. The visual quality of the rendered image is based quite strong on the talents of the person who builds the level. He / she should have insight in which tile types can be blended into each other without creating a fake look. Also he has to know how large an elevation difference can be without stretching the texture too much, since large elevation deltas stretch the tiled texture too much resulting in a visually disturbing image. Further, there are not only are there less features completed than I would have like there to be, but the features are not able to do what they are able to do in theory. For example: I would have liked the terrain to be able to reflect the change of time in the day (color changing and shadows getting shorter/longer based on the position of the sun) but the algorithms just are to slow to update that kind of stuff on run-time. The lack of features is mainly that I have some code for loading meshes (with animation and hierarchical data), but I did not have the time to implement it so that it can actually be used. The terrain s water is not ready yet which makes the terrain look a bit empty as well. The project required me to work for around 160 hours. Suffice to say that I did not make this by a long long long shot, I think a multiplication of about 5 or 6 times that amount is more appropriate. Nevertheless I had my fun, gained some experience and finally got a terrain editor that had a lot of positive responses from the people I know and care about. Well, it has been fun. But to all good things in life must come an end, and here it is. I guess I will go to bed now where my girlfriend is already sleeping and spend the weekend with her again, since I really have not given her the amount of attention she deserves the past few weeks. Goodnight. Ebor Jan Folkertsma

56

Appendix A: System specification


Below is a list of the system specifications I will target for the project. Note that these specifications are not strict guidelines, since tweaking a software product into a certain category of system requirements is an elaborate job in its own right. Nevertheless the specifications give some indication of what kind of system is required.

Required
System: Processor: Memory: Hard Disc: CD/DVD: Graphic Card: Input: Windows 2000 / XP Pentium III 1000 MHz, or equivalent / better processor 128 MB RAM 500 MB 4x speed GeForce II MX or better, with at least 16 MB of video memory. Keyboard and mouse (3 mouse buttons preferred)

Recommended
System: Processor: Memory: Hard Disc: CD/DVD: Graphic Card: Input: Windows 2000 / XP Pentium III 1500 MHz, or equivalent / better processor 256 MB RAM 500 MB 4x speed GeForce III/IV, ATI Radeon 8500 or better, with 64 MB of video memory. Keyboard and Mouse with 3 mouse buttons

57

Appendix B: Development tools specification


Below is a list of tools I intend to use during the construction of the project. The list is divided in major tools and the libraries for the programming languages. A major problem I encountered while making the list is that most good software, for example Adobe Photoshop or 3D Studio Max, costs a lot of money. Unfortunately the University of Twente does not have internal or student licenses for most of this good software and I had to look for replacement products instead. The list below will therefore contain some names that have a * in front of it, meaning that I prefer to use that software and will use it wherever possible when the appropriate licenses are available.

Programming IDE DevCPP with the MinGW compiler (www.bloodshed.net) * Borland C++ Builder (www.borland.com) * Microsoft Visual Studio .NET (www.microsoft.com)

Programming Libraries OpenGL (www.opengl.org) Boost (www.boost.org) SDL (www.libsdl.org)

Modeling Programs MilkShape3D (http://www.swissquake.ch/chumbalum-soft) * 3D Studio Max (www.discreet.com)

Painting Programs The GIMP (www.gimp.org) * Adobe Photoshop (www.adobe.com) * Paint Shop Pro (www.jasc.com)

58

Appendix C: References
Books
3D Games (Real-time rendering and Software Technology), Alan Wat, Fabio Policarpo, Copyright 2001 by ACM Press, A division of the Association for Computing Machinery, Inc. OpenGL game programming, Kevin Hawkins, Dave Astle, Copyright 2001 by Prima Tech. OpenGL Programming Guide (The Red Book), Dave Shreiner, Mason Woo et al, Copyright 1994 by Silicon Graphics, Inc. OpenGL Reference (The Blue Book) , Dave Shreiner, Mason Woo et al, Copyright 1994 by Silicon Graphics, Inc. The OpenGL Extensions Guide, Eric Lengyel, Copyright 2003 Charles River media The C++ Standard Library (A tutorial and reference), Nicolai M. Josuttis, Copyright 1999 by Addison-Wesley.

Websites
Boost libraries URL: http://www.boost.com C Plus Plus resources URL: http://www.cplusplus.com DinkumWare C++ specificatie URL: http://www.dinkumware.com OpenGL site URL: http://www.opengl.org Simple direct media (SDL) URL: http://www.libsdl.org

59

S-ar putea să vă placă și