Game Creation with XNA/3D Development/Landscape Modelling

= Landscape Modelling =

Introduction
How do we implement and model a landscape which is based on XNA Framework into our game? This WIKI-entry will deal exactly with this problem. By example it will be shown how to create a landscape using a HeightMap. Furthermore we will create a texture, drag it onto our landscape and write loads of source code. Finally there will be some tips regarding topics related to Landscape Modeling.

A HeightMap (Wikipedia: HeightMap) is nothing else than a greymap. So to say a 2D texture which points out the heights and depths of our landscape. Every pixel of the greymap is between 0 and 255 indicating our elevation. To create such a map use a program like Terragen.

Terragen is a program used to create photorealistic landscape-images pretty quick. However it also is a perfect tool to create a HeightMap. Terragen is available in 2 versions (date: 05.06.2011) one version which has to be paid for - Terragen 2 and a free version Terragen Classic. For our needs the free version is perfectly ok.

Creating HeightMap
Enough of the introduction – let’s get started. After downloading and installing Terragen Classic we can see the following menu:



On the left hand side we can see the buttons provided by Terragen. First step is to click on „Landscape“ and a new window will open up. Here we click on “Size” to adjust the size of our HeightMap – 257x257 or 513x513. Tip: If you already have a skybox implemented, use the size of your skybox image. Next we click on “View/Sculpt” to model our HeightMap. You will see a black picture with a white arrow in it – that’s your camera perspective. You can adjust the perspective as you like by moving the arrow to the desired position. To start painting your terrain you need to click on “Basic Sculpting Tool” (1) located at the top left corner of your window. Now you can start to draw your landscape. Something like this should be the result:



If you are not satisfied with your result you can always click on “Modify” within your landscape window and adjust certain settings like maximum height of your mountains. Another useful function is “Clear/Flatten” which resets your HeightMap so you can start all over again. When you are done painting your HeightMap, click on the button “3D Preview”. This is what it should look like (depending on what you have drawn):



To save your HeightMap click on „Export“ in the landscape menu and choose „Raw 8 bits“ as Export Method (1). Click on “Select File and Save…” name your HeightMap and save it to your Hard Drive.



We are nearly done with our HeightMap, which is now in .raw format. Finally we need to convert this format into something else by using a program like Photoshop or the free tool “XnView” (www.xnview.de). Change your .raw format to .jpg, .bmp or .png because the “default Content Pipeline” from XNA can handle these formats as “Texture2D”.

Creating Texture
What would our landscape be without texture? Therefore, let’s use Terragen to create one. To do so open the “Rendering Controls” within your Terragen menu.

First thing to do is adjust the size using „Image Size“ (1) depending on whatever size you made your HeightMap (512x512 or 256x256). In the Rendering Control Window, at the bottom right corner, position your camera so you can actually see you floor (2). To directly face the floor use the value -90 for pitch (3). This makes you directly look at your floor. Furthermore set the “Detail” – slider (4) to maximum in order to get the highest quality when rendering. Click on “Render Preview” (5) to get a preview of your texture. Alternatively you can open your “3D Preview” again, but your texture will not be shown rendered.



Any black spots on your texture will probably be shadows cast on your terrain. Click on the button „Lightning Conditions“ in the Terragen Menu and uncheck „Terrain Casts Shadows“ and „Clouds Casts Shadows“(1) to make them disappear.



Now you are done and can click on „Render Image“ (6) in your “Rendering Control”. Terragen now renders your texture which should look something like this:



You can also change the colour of your texture. To do so click on the “Landscape” button in your Terragen menu. Choose “Surface Map” (1) and click on “Edit” (2). The “Surface Layer” window will open up. Now click „Colour…“(3) to choose your colour. When you are satisfied with your texture save it to your Hard Drive.



Play around with the settings, render it and check the changes. If you choose the colour to white, this is what your texture should look like:



Now we are done with the basics and finally reached our first goal – our own HeightMap and texture:

= Implementation in XNA =

From now on we start working on implementing the HeightMap and the texture into XNA code. But to actually see something we need to start by programming a camera.

Creating Camera Class
We create a new Project in Visual Studio 2008 and add a new class named „Camera“.

We start of by assigning some class variables. A matrix viewMatrix for the camera view and a projectionMatrix for the projection. The projectionMatrix converts the 3D camera view into a 2D image. To position our landscape later on, we will need another matrix terrainMatrix. Furthermore it would be nice if we could move or rotate our camera over our landscape. Therefore we declare Vector3 variables for position, alignment, movement and rotation of our camera.

The camera constructor gets parameters to initialize all these variables.

Now if you ask yourself what exactly the methods CreateLookAt, CreatePerspective, CreateTranslation are doing, check the class library of XNA Framework -> XNA Framework Class Library Reference. All methods are clearly described there. Keep the XNA Framework class library in mind to check all the methods unclear to you, because not all methods used in the source code will be explained in detail.

To exercise this at least once we use the method CreateTranslation. Go to Matrix.CreatePerspective Method (Single, Single, Single, Single) and you will find a detailed description of all the parameters used by the method as well as their return values.



Back to our camera class. Next step is to create an Update method which will get a number as parameter. In this method we define the movement and rotation of our camera and calculate our new camera position at the end. We do that because when we create a camera in our Game1.cs later on, we can move our camera by using keyboard inputs. Every keyboard input sends a number which will be processed by the camera’s Update method.

Finally our camera gets a Draw method. In this method we pass our landscape to ensure it gets displayed later on.

Before we can start to write our Terrain.cs class we need to implement the method SetEffects which is used by the Draw method. BasicEffect is a class in XNA Framework which provides rendering effects to display objects.

Now our Camera.cs class is ready and to actually see something we now start to write our Terrain.cs class.

Overview Camera.cs class
This is how the complete Camera.cs class should look like.

Creating Landscape Class
Create a new class and rename it Terrain.cs. Again we start by defining class variables we will need. We will need Texture2D variables for our HeightMap and our texture image as well as variables to work with the textures, especially arrays.

In the constructor of our Terrain.cs we call the GraphicsDevice unit in order to be able to access it in our class.

Now we create a method which will get our textures (this will happen from the Game1.cs class and will be explained later) and calls other methods so we get closer to our landscape. So let’s write the missing methods.

We start by implementing the SetHeight method which will get the greyscale from each pixel of the texture, indicating its actual height, and writes them into the heightMapData[] array. The complete method:

To get the intensity of each greyscale it is suffice to get the value of a single colour, either red, green or blue – which one you choose is up to you. To not get to much difference in altitude you can divide your colourvalue by a value. Hence this line:

It also works the other way around. When you multipliy with a value you will get a higher difference in altitude.

The next two methods deal with the creation of indices and vertices. SetVertice creates the area of our landscape using triangles. An area consist of two triangles. A triangle can be described by 3 numbers which are called indices. These indices of a triangle are assigned to vertices. If you need a refreshment in that matter go check Riemer’s XNA Tutorials -> Recycling vertices using inidices.

In our method some strange mathematical stuff is used to calculate correct indices. Play around a bit and check out what happens when you change certain values.

The SetVertices method calcualtes the 2D-position for each vertex the texture should be applied. The heights and depths will be assigned using the data from the heightMapData[] array.

Now we implement a SetEffects method in which we use a new shader object of type BasicEffet (Wikipedia: Shader). Its texture properties get assigned to our terrain texture and its display gets activated.

To actually draw the landscape our terrain.cs class gets an own Draw method. From here we call the method DrawUserIndexedPrimitives(from GraphicsDevice class from XNA) which is extremely powerful and contains a pretty long list of parameters. First the type of object that is to be drawn. A collection of triangles is meant when using TriangleList. Followed by our array containing the vertices. The next parameters take the starting point and the ammount of our vertices. Next is the array with our indices and at the end the number of the first triangle and the ammount of triangles.

Last but not least we need to adjust our Game1.cs in which we now call our camera and our terrain to reach or goal to see our landscape.

Overview Terrain.cs class
Prior to that an overview of the complete Terrain.cs class:

Adjusting Game1.cs class
Before we start we import our HeightMap as well as our texture image into VisualStudio2008. Right click on content in your project-explorer. Choose "Add" –> "existing Element…" in the menu popping up. Choose your images and import them. You now should see your HeightMap and your texture image listed under Content. Now create your camera and your terrain as class variables.

To let VisualStudio2008 know where to find your images, add the following line to the constructor:

Next initialize your camera and your terrain using the Initialize method.

If you later dont see anything you might need to adjust your Vector3 vectors which are passed into the camera class.

The following line from the LoadContent method is used to load the HeightMap and texture image into your terrain class:

Because we programmed our camera class forward-looking and want to move our camera over our terrain, we simply need to define the keys for movement in our Update method.

Last but not least we need to tell the camera’s Draw method to draw our landscape.

Overview Game1.cs class
Congratualtions – we are done.

As result of your work you should now see your landscape with your HeightMap and your texture generated by the Debugger. Furthermore you can move your camera over your terrain to confirm to really have heights and depths.

Now you can easily replace your whole landscape by simply using a different HeightMap. Same applies for the texture. Just use the new names of your new images as parameters in the SetHeightMapData method in your Terrain.cs class.

Related topics
Unfortunately the Basic-Shader from XNA (BasicEffect) can handle only one texture. To improve your landscape you could now write your own EffectShader file which would handle more than one texture. If you are interested in shaders check Game Creation with XNA/3D Development/Shaders and Effects. You could make your landscape more interesting using multitexturing.

It is also possible to create a landscape using a 3D Modeling Software and import it as .x or .fbx file. Doing so will require more CPU-Power and knowledge of 3D Modeling Software though. Check Game Creation with XNA/3D Development/Importing Models.

Another really complex topic would be collision detection for an object moving on the surface of your landscape. Check Game Creation with XNA/Mathematics Physics/Collision Detection. A short introduction using the image below.



The blue circle is the object (maybe your game character). This object always has to request the y-position of you landscape for the direction it is moving in (green line). To get a smooth movement when the altitude of your landscape changes you need to interpolate (Wikipedia: Interpolate) the y-value of your object’s vector at its current position with the new y-value of your landscape’s vector (the destination). The y-value of the landscape in the image changes from 15 to 23.

You can find more on this topic and some code here:

Collision Series 4: Collision with a Heightmap

Collision Series 5: Heightmap Collision with Normals

= Links =


 * http://en.wikipedia.org/
 * http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series1/Terrain_from_file.php

= Literature =


 * Microsoft XNA Game Studio 3.0, Chad Carter
 * Microsoft XNA Game Studio Creator’s Guide Second Edition, S. Cawood and P. McGee
 * Spieleprogrammierung mit dem XNA Framework, Hans-Georg Schumann

= Authors =

RayIncarnation