Terrain Building Tutorial

16 posts in this topic

A few guys now have expressed an interest in terrain building since I first brought it up so I figured I'd compose a tutorial covering the basic bits that I have learned so far. This is by no means comprehensive but it should put you in good stead to start your own experiments with terrain builder and I'll add more sections as I continue to figure this stuff out.


A terrain in ARMA is a simple collection of images that are interpreted by the game engine to make a virtual 3D landscape. If you think about that then, anyone who can produce images can produce a terrain. Like most things, it usually sounds more impressive than it actually is. A subdermal haematoma sounds quite serious but is actually just a bruise!

The main problems in producing a decent terrain are the quality of the images and the time taken to populate the map with objects. While the time taken to populate can't really be helped, the quality of the images is on you. The more time you can put into this, the better the end result will be.

This cannot be stressed enough. If you want a decent job, this will take time. While generating fictional terrain can be fairly quick, a geographically accurate representation of a real world location will take months rather than days.

Required Tools

Like any job we need a given selection of tools. I've listed those tools that are free but there will obviously be others that can do the same job for a cost:

Terrain Image Generation:
L3DT (Standard or Pro) -> http://www.bundysoft.com/L3DT/downloads/
QGIS (Used for real world geo-data conversion) -> http://www.qgis.org/en/site/forusers/download.html
Google Earth (Used for real world geo-data conversion) -> https://www.google.co.uk/earth/

Image Editing:
GIMP or an equivalent that can import png/jpg/tiff files and can export png/bmp files -> https://www.gimp.org/

Config Editing:
Decent text editor such as Notepad++ or dedicated coding software such as Visual Studio Code -> https://notepad-plus-plus.org/download/v7.2.html

Project management/PBO work:
ARMA 3 Tools -> available on Steam under "Tools"

Point to note here on ARMA 3 Tools. A lot of modders out there will swear that the BIS tools are substandard and that anyone wanting to build mods should use Mikeros PBO tools. I personally had nothing but problems with Mikeros tools and to this day they don't work for me. Not only that they impact other things we will use later on. Both sets
of tools essentially do the same thing so this really boils down to personal preference. Mikeros tools can detect errors that the BIS tools do not but then again you need a paid subscription to get the full range of use. The BIS tools by contrast are free but need more care from the user to ensure things are done properly.

This tutorial will be written using the BIS tools.

P Drive

The infamous BIS P Drive is a virtual partition on your HDD that emulates your ARMA installation. Certain tools, terrain builder included, use the P Drive format to reference the objects you put into your map. While using the P Drive isn't strictly speaking necessary, it certainly makes life significantly easier.

The BIS tools set will configure the P Drive for you automatically:
Select Project Drive Management:

Tick the "Mount the work drive (P)" button and click run:

Let this do it's thing which may take a while. With the P Drive setup we need the game data. This will make referencing things like buildings easier later on. The game data can be extracted from the same Project Drive Management section. Select the "Extract Game Data" button and click run. Again this will take some time and will require a MINIMUM of 20GB HDD space. This may sound excessive but it will allow you to quickly and easily reference all content from ARMA 3. It is definitely worth it.

Finally we will need Buldozer. Buldozer is a 3D tool used in different ways by different tools. For terrain building it allows us to see a 3D render of the terrain which we can then edit as we need. Buldozer is installed in the same way as the other stuff we've just done. With these steps done, the P Drive is configured. When you shut down your PC it will be "unmounted" meaning it disappears. Don't worry about it, you don't need to go through all of this again. Once the drive is configured, you need only "mount" the drive using the "Mount the project drive" button:

You can set it up to mount automatically on system start but that's your call.

Where to start

Having all the tools setup is one thing but where the hell do we start? If you think back to the overview, the terrain is made from simple images. To start then, we need these images. For a real world geo-data map, there is a different process which I will cover at a different date. For now, I'll be using L3DT to produce a fictional terrain.

L3DT is a terrain generation program but again, all it does is produce images. The best thing about L3DT is that it can generate every image we need AND they will all match up to each other so we reduce the amount of image editing needed later. L3DT can also procedurally generate our terrain for us further reducing the workload.

So then to answer the big question, we start in L3DT.


Make yourself a folder somewhere sensible and call it whatever you like. This will be the folder we use for our L3DT files. With the folder created open L3DT and create a new project. This will open the project creation wizard:

The options can be used to generate all sorts of terrains but for this we will use Designable Map. This will generate everything we need for our terrain.

The next page of the wizard dictates the size of the heightfield image in pixels. The pixels in the heightfield image are multiplied by a resolution in terrain builder to give us our terrain size. L3DT standard limits this size to 2048x2048px. We're only making a small map to begin with so a size of 1024x1024 is fine.

Next we need to setup the horizontal scale. This dictates how the pixels will relate to the terrain in game. A horizontal scale of 10 for example makes each pixel 10x10m. Added up across our terrain then we get a terrain size of 10x10km, not a bad size to start with.

Finally leave the check boxes empty. We don't want the map tiled nor do we want to wrap the edges:


Hit the next button and we go to the design map size. This will not effect our project so simply leave the defaults and hit next.

This brings us to the Design Map Parameters page. These options will dictate how our terrain is generated so I'll break the options down:

  • Average Altitude: This is the average altitude of the map funnily enough. You can generate more sea, or more land by moving the slider
  • Altitude Range: This is the range between the lowest possible point on the map and the highest. The higher this is, you will generate taller mountains
  • Scale of Features: This dictates the "size" of the terrain features. This scale is horizontal. As an example, if you use tiny scale any mountains will be thin, almost needle like, like the deserts of America. If they were larger, they can become less steep and will resemble mountain ranges.
  • Noise Strength: L3DT generates the terrain by using something called fractal noise. This is an algorithm that generates peaks and troughs that then become our hills and valleys. The Noise Strength option dictates the range in size of these peaks and troughs.
  • Noise Shape: Again this ties into fractal noise. This option changes the shape of our peaks and troughs. If you move toward rolling, the shape will be gentle. If you move toward fractal, the shape will become jagged and craggy.
  • Cliffs and Terraces: This dictates the amount of "flat" land produced. A terrace is a patch of flat land, a cliff is flat but also vertical. While terraces give us pre-made flat areas for building towns, this needs to be limited or the map can start to look like a Warhammer gaming board. Cliffs can be made to look real later on by using rock objects rather than a plain texture which will just look like a painted wall.
  • Erosion: The erosion modifier is quite clever. Once the terrain is produced the erosion modifier is applied. Rivers will cut into valleys, coastline will be eroded by the sea and mountains will shrink. The higher the value, the more weather beaten the map will look.
  • Lakes: This dictates the amount of inland lakes. ARMA 3 does not support bodies of water above the water table so care needs to be taken here or we'll end up with a patch of blue terrain that should be a lake but is actually solid ground.
  • Default Climate: This dictates the "terrain type" given to each pixel. Temperate climates will have more grass while coastal climates will have more sand. This will change the appearance of the texture map.

Set these options up how you fancy then hit next. Mine are below:


Next we have the calculation queue. This dictates what we want L3DT to produce. Select everything then hit next.

Next is the water options. Just leave the defaults for now and hit next.

Next is a summary of the water options. Again just hit next.

Next up is the light map options. Again we don't need to change these so hit next for the next 3 pages.

The final page is the texture settings. We will use the texture as our main satellite image later. To give us a decent level of image quality then, make sure the "Make High Resolution Texture" box is ticked.


Make sure the tile option is NOT checked.

With this done, hit next and L3DT will generate our terrain. It can take a while so go for a smoke break or something. Once it's finished you should get something like:


Obviously this is very basic. You can edit this in L3DT to tweak the map but for this tutorial I'm just going to stick with this.

Save your project into the folder you created above and navigate there. You'll see something like:


This seems like a lot of crap and it is for the most part. We only need the highlighted files. The TN file is our normals file and the TX file is our texture file. We do however need 2 other images, the mask and the heightfield.

First up we'll get the heightfield. If you look on the tabs in L3DT you'll see a tab called Heightfield. This is the heightfield image for the project. What we need to do is export it in a format we can use in terrain builder. Right click on the heightfield tab and select Export Layer. The default value is of no use to us, terrain builder needs an ASC file. Use the drop down menu to select ASC format and give it a name:


The final image we need is a mask. This is used by terrain builder, and ultimately the game engine, to lay out the textures on the ground to turn our terrain into a properly rendered world. How the hell do we get this then? Luckily L3DT has a solution, the attributes map.

The attributes map assigns each pixel a colour relating to the underlying terrain. Grass will have a value, sand will have a value, you get the idea. We can use this data to create our mask image but first we need to export the attributes map as L3DT does not export this by default. Right click the attributes map tab and select Export Layer. As we did with the heightfield, give it a name and save it as a PNG file.

This will create 2 files, the image itself and * palette.txt where * is the name you gave it. If you open this text file then you will get something like:

R, G, B, Climate, Land type
230, 230, 120, "Temperate (coastal)", "Beach sand",
175, 160, 130, "Temperate (coastal)", "Pebbles (sea)",
120, 120, 121, "Temperate (coastal)", "Underwater rock (sea)",
120, 121, 120, "Temperate (coastal)", "Underwater rock (lake)",
120, 122, 122, "Temperate (coastal)", "Coastal rock",
140, 195, 80, "Temperate (coastal)", "Grass",
140, 185, 70, "Temperate (coastal)", "Steep grass",
110, 190, 80, "Temperate (coastal)", "Steep lush grass (2)",
140, 185, 72, "Temperate (coastal)", "Steep lush grass (3)",
160, 200, 90, "Temperate (coastal)", "Coastal grass",
158, 198, 90, "Temperate (coastal)", "Coastal grass (2)",
155, 195, 90, "Temperate (coastal)", "Coastal grass (3)",
156, 194, 75, "Temperate (coastal)", "Steep coastal grass",
170, 190, 80, "Temperate (coastal)", "Dry grass",
160, 195, 80, "Temperate (coastal)", "Dry grass (2)",
150, 195, 80, "Temperate (coastal)", "Dry grass (3)",
170, 180, 70, "Temperate (coastal)", "Steep dry grass",
150, 180, 80, "Temperate (coastal)", "Steep dry grass (2)",
120, 120, 120, "Temperate (coastal)", "Cliff face",
80, 80, 80, "Temperate (coastal)", "Steep cliffs",

This data is the RGB colour format for each type of terrain pixel and a description of what it represents. We can use these values to create a usable mask in our imaging software.

A point to note on L3DT is that you don't have to stick with what it gives you. You can edit the terrain as you see fit and reproduce the images until you get the terrain you want. This will become evident later on as we encounter things like the edge of the map but this will be expanded upon at a later date.

We're now finished with L3DT.

Mask Image

With our basic images created we now need to turn our exported mask into something usable by terrain builder. Terrain builder works best when you give it extreme values for the mask. If 155/0/0 is red then 255/0/0 is RED, like fucking RED and this is what terrain builder prefers. Furthermore you can only have a given number of surfaces per terrain tile so we need a way of limiting the amount of texture types we have on the mask or we may run into problems later.

If you look at our pallette.txt file you can see there are lots of values that can be merged without too much impact. Do we really need 3 types of dry grass? No, not really. If we merge the values that are comparable to each other we can reduce the amount of surfaces we need and thus prevent problems in terrain builder later on. Look at our palette.txt file:

R, G, B, Climate, Land type
230, 230, 120, "Temperate (coastal)", "Beach sand",                           Sand
175, 160, 130, "Temperate (coastal)", "Pebbles (sea)",                       Sand
120, 120, 121, "Temperate (coastal)", "Underwater rock (sea)",        Sand
120, 121, 120, "Temperate (coastal)", "Underwater rock (lake)",       Sand
120, 122, 122, "Temperate (coastal)", "Coastal rock",                         Sand
140, 195, 80, "Temperate (coastal)", "Grass",                                       Grass
140, 185, 70, "Temperate (coastal)", "Steep grass",                            Grass
110, 190, 80, "Temperate (coastal)", "Steep lush grass (2)",             Grass
140, 185, 72, "Temperate (coastal)", "Steep lush grass (3)",             Grass
160, 200, 90, "Temperate (coastal)", "Coastal grass",                        Scrub land
158, 198, 90, "Temperate (coastal)", "Coastal grass (2)",                  Scrub land
155, 195, 90, "Temperate (coastal)", "Coastal grass (3)",                  Scrub land
156, 194, 75, "Temperate (coastal)", "Steep coastal grass",             Scrub land
170, 190, 80, "Temperate (coastal)", "Dry grass",                               Dry Grass
160, 195, 80, "Temperate (coastal)", "Dry grass (2)",                         Dry Grass
150, 195, 80, "Temperate (coastal)", "Dry grass (3)",                         Dry Grass
170, 180, 70, "Temperate (coastal)", "Steep dry grass",                    Dry Grass
150, 180, 80, "Temperate (coastal)", "Steep dry grass (2)",              Dry Grass
120, 120, 120, "Temperate (coastal)", "Cliff face",                             Rocks
80, 80, 80, "Temperate (coastal)", "Steep cliffs",                                Rocks

You can see the idea. We take the values from the pallette and merge them into surfaces that cover all the alike pixels. We've gone from 20 surface types to 5. We need to do this due to limitations in terrain builder and the game engine which we will cover later on.

Now then we need to take each of the values from the palette and assign them a value for our own surface:

R, G, B, Climate, Land type                                                                                                              New RGB
230, 230, 120, "Temperate (coastal)", "Beach sand",                           Sand                              255/0/0
175, 160, 130, "Temperate (coastal)", "Pebbles (sea)",                        Sand                             255/0/0
120, 120, 121, "Temperate (coastal)", "Underwater rock (sea)",         Sand                             255/0/0
120, 121, 120, "Temperate (coastal)", "Underwater rock (lake)",        Sand                             255/0/0
120, 122, 122, "Temperate (coastal)", "Coastal rock",                          Sand                             255/0/0
140, 195, 80, "Temperate (coastal)", "Grass",                                        Grass                            0/255/0
140, 185, 70, "Temperate (coastal)", "Steep grass",                             Grass                            0/255/0
110, 190, 80, "Temperate (coastal)", "Steep lush grass (2)",               Grass                            0/255/0
140, 185, 72, "Temperate (coastal)", "Steep lush grass (3)",               Grass                            0/255/0
160, 200, 90, "Temperate (coastal)", "Coastal grass",                          Scrub land                   0/0/255
158, 198, 90, "Temperate (coastal)", "Coastal grass (2)",                    Scrub land                   0/0/255
155, 195, 90, "Temperate (coastal)", "Coastal grass (3)",                    Scrub land                   0/0/255
156, 194, 75, "Temperate (coastal)", "Steep coastal grass",               Scrub land                   0/0/255
170, 190, 80, "Temperate (coastal)", "Dry grass",                                  Dry Grass                    255/255/0
160, 195, 80, "Temperate (coastal)", "Dry grass (2)",                            Dry Grass                    255/255/0
150, 195, 80, "Temperate (coastal)", "Dry grass (3)",                            Dry Grass                    255/255/0
170, 180, 70, "Temperate (coastal)", "Steep dry grass",                       Dry Grass                    255/255/0
150, 180, 80, "Temperate (coastal)", "Steep dry grass (2)",                 Dry Grass                    255/255/0
120, 120, 120, "Temperate (coastal)", "Cliff face",                                Rocks                           0/255/255
80, 80, 80, "Temperate (coastal)", "Steep cliffs",                                   Rocks                           0/255/255

So we now have to recolour each pixel to the corrected value, see you next year......joking. Obviously if you did this by hand it would take an age. Luckily GIMP has a function to do this in minutes, colour exchange:


Using this tool we simply enter the value to change and the value to change to. This will change the colour for every pixel of the given colour. Work your way through your mask image and change your colours to suite, remember to use extreme pixel values either 0 or 255. Once complete you should have:

                                                             Before                                                                                                                                              After


That's all we need GIMP for in this tutorial. Obviously you could improve the texture image while your here if you wish. As was said at the beginning a good job can only be done with a lot of time and effort.

Terrain Project Creation

Ok, with our images all sorted we are ready to jump into terrain builder. Before we can do this however we need somewhere to save our project. Go to your P drive and create a folder. Name it something memorable, you'll use this as a reference point for everything in the mod. You can create sub-folders etc for organisation but, and this is important, EVERYTHING IS REFERENCED FROM P:

When I say everything I mean EVERYTHING. Textures, header files, materials, objects, everything. You need to know the exact path from the P drive root to where you put things for later when you reference them. In my case I'll call my island GOL_Tutorial. So then everything to do with the tutorial will be referenced GOL_Tutorial\something\something else\some file.whatever.

If you think about it this makes sense. P drive is an emulation of your ARMA installation and all mods are referenced from the ARMA 3 main folder.

So then with your folder created, it's time to head into terrain builder. This is accessed from the ARMA 3 tools.

Terrain Builder

Terrain Builder is the program that will turn our images into the files that the game engine needs to make the map. It is not however without it's issues. It is slow and is prone to crashing so it is nearly always better to change things in an external program and re-import later. It can also be beneficial to close as many background programs as possible.

The first rule of terrain builder? SAVE EVERYTIME YOU CHANGE SOMETHING!! This way when (not if) it crashes, you don't lose too much.

Now then, the first thing we need to build a terrain is a mapframe. It should be one of the only options you can select at the minute so select Mapframes and Add Mapframe. You'll be greeted with the UTM selection dialog. Leave this as the default. Any changes to real world location are done later in the config or you can break the way roads and runways work.

You should now have the Mapframe Properties Page. This lays out all the properties of the mapframe and subsequently the map itself. First up,  give it a logical name. Remember what we said about referencing, the name should match the name of the folder you used in P: So in my case, the name is GOL_Tutorial. Next set the output directory to the folder you created in P: Hit the "Create Sub-Folders" button and TB will create all the sub-folders we will need in the folder we specified. Next up set the Eastings to 200000 and the Northings to 0.


There is a point to note here. Like the UTM selection, we use a specific value for our world position. This is again due to the way the roads are handled by the game engine. If you use other values your roads may not display or may cause unwanted AI behaviour. Best to stick with what works as the real world position can be changed later in the config to affect things like stars/tides etc.

Flick to the samplers page, it's here that we configure our images. The first entry is the size of the terrain grid and the cell size. Remember in L3DT we had a horizontal scale of 10m? this relates to this cell size. Set the grid size to our image size, 1024 and the cell size to our horizontal scale of 10. This should give us a terrain size of 10km or more specifically 10240m.

Next we set the image size of our satellite and mask images. This should match the actual size of the image, 1024, and gives us a resolution of 10. This means that each pixel in the image is worth 10m in the game world. Now, this should obviously be as small as possible to improve the quality of the map graphics but lowering it too far can cause performance issues, especially for aircraft. 10 is a reasonably decent trade off so we're good.

Next we select the number of tiles TB will generate for ground texturing. Just leave the default.

Finally we come to the Texture Layer size. Now, this is a weird one. The texture layer is a file that is generated by TB in order to draw the ground textures in game. Obviously smaller values would lead to sharper, better images but there is a known bug here. A "tartan" effect can occur in game if you mess about with this too much. The established best practice is to set this number to as close to 40 as possible. In our case you should be able to set it for exactly 40 so do that.


The last page is the processing page. We can't do anything here just yet but we need to "build the terrain" in order to save the mapframe. Hit "Rebuild Terrain" then hit ok to finalise the mapframe. Once the dialog closes, SAVE YOUR PROJECT. Save it in the project directory on P: in the purpose built folder "terrain builder files" in the source directory of the project folder.

Exit terrain builder now so it doesn't crash.

Materials and Textures

Ok, we have a 3D image of our world and we have some images of how we want it to look. What we need now are the "bricks" that TB will create our world from. These bricks are "materials".

Materials revolve around the .rvmat file. These files contain shader and texture data and are then used by the game engine to "paint" the scenery making our world look real. You can, if you have the talent, create your own textures and materials but ARMA has it's own selection. Navigate to the A3 directory in P: that was created when we extracted the game data. If you then access the map_data file you will find a sollection of .rvmat files and .paa files. The .paa files are textures that have been saved into a particular format using TexView 2, one of the tools from the BIS set. Each texture has 2 files, a _co file and a _nopx file. The _co file contains the texture colour, the _nopx file contains pixel normal data for shading.

What we want here is a texture that fits our chosen surfaces in our mask. So then if we take my grass surface, we need a grass texture. Scanning through the list we will find gdt_grass_green. If you open this in TexView you will see a nice grass image, this will do nicely.

What if ARMA doesn't have what we need? Lets say we need some snow. Now there is no snow in the Mediterranean nor in the Pacific so we're not going to get this from ARMA. Think about the ARMA files for a second, all we need is a _co image, a _nopx image and an rvmat file. Surely we can do this ourselves? Of course we can. The _nopx image is normal data for shading and relies on the _co file to do it's thing. The rvmat file ties these images together so we must start with the _co image. Remember the _co image is just a picture and as such we can make it ourselves.

Some people may be capable of producing this image for themselves, I however draw like my 3 year old. Instead then I download textures from the net. http://www.textures.com/ is a great source of free textures, all you need do is register (free) and you can download a set number of images per day.

To make the snow then we need a snow texture. I have downloaded http://www.textures.com/download/snow0076/42138 for mine. It's seamless meaning it will join with no issues. We can't however use it straight out of the box.

First of all it isn't the right size. Think back to _gdt_grass_green, it's size is 2048x2048px. We need ours to match that. Secondly textures need to be in .paa format. We can deal with this in TexView2 as long as our image is a .png file. Our snow texture however is a .jpg. Finally we need a way to produce a normals image from a colour image. The solution, our friend GIMP.

First up we need the plugin to produce normals. This can be downloaded from https://code.google.com/archive/p/gimp-normalmap/downloads The zip file contains installation instructions and you're going to want to install this before going any further.

Once ready open the texture image in GIMP. First order of business is to re-size it. A simple scale action is sufficient. Export the image as a .png file with the _co suffix. For example: custom_snow_co.png

Now for the normal image. Keep the project open and hit filters->map->normal map. This will bring up this box:


Play about with the settings and make sure to use the 3D preview to see how your texture will look. One point to note here, the plugin will crash unless your image is square. Below are the settings I used:


Hit ok once you're happy with the result and export this as a .png with the _nopx suffix. For example: custom_snow_nopx.png

Now to convert these images. Open one of the images in TexView2 and save as. Change the file extension from .png to .paa. Repeat this for the other image.

Copy these files to the data folder of your project directory.

With the images completed we now need the rvmat file. The rvmat is a little block of code that dictates how the shaders in game will interact with our texture:

class Stage1
    class uvTransform
class Stage2
    class uvTransform

This looks a bit daunting if you know nothing of code but then again I know bollocks all about shaders. The only thing we're interested in here are the 2 Texture lines. As you can see I set the first stage to reference the _nopx image and the second to the _co image. Create a simple text file in the same location as your images. Copy the above and make sure to reference your own images, making sure to use the relative file path to P: Save the file, job done.

Obviously as you play around in your own project, try changing the shader values here to see what effect they have.

Here's the texture in game:


Not a bad job considering it was all for free. The quality of the texture could be improved by tiling the image to bring it up to size rather than scaling it.

A final point on texures. A texture is a simple image and as such you can use ANY image. An entirely viable method of extending this would be to photograph terrain IRL and use the photo as the _co image. As long as the image transfers and scales correctly, there should be no reason why you couldn't do this.

The Code Begins

Now, we need to copy over the textures. Make sure you copy the rvmat, _co and _nopx file for each of your chosen textures. Paste them into the data folder of the project directory. Now we produce our layers so we need a layers.cfg file. Create a simple text document in the source directory of the project folder and call it layers.cfg. Note you have to change the file extension. Notepad++ will still be able to open it though so don't panic. Inside the file we need something like this:

class Layers
  class GOL_Tutorial_Sand
    texture = #(rgb,1,1,1)color(0.5,0.5,0.5,1,cdt);
    material = "GOL_Tutorial\data\gdt_beach.rvmat";
  class GOL_Tutorial_Grass
    texture = #(rgb,1,1,1)color(0.5,0.5,0.5,1,cdt);
    material = "GOL_Tutorial\data\gdt_grass_green.rvmat";
  class GOL_Tutorial_Scrub
    texture = #(rgb,1,1,1)color(0.5,0.5,0.5,1,cdt);
    material = "GOL_Tutorial\data\gdt_dirt.rvmat";
  class GOL_Tutorial_Dry
    texture = #(rgb,1,1,1)color(0.5,0.5,0.5,1,cdt);
    material = "GOL_Tutorial\data\gdt_dry_grass.rvmat";
  class GOL_Tutorial_Rocks
    texture = #(rgb,1,1,1)color(0.5,0.5,0.5,1,cdt);
    material = "GOL_Tutorial\data\gdt_rock.rvmat";

class Legend
  class Colors

Don't get scared it's really straight forward. We create a class for each of our surfaces, then we set each class material to the copied material from the A3 data. Note how we reference the data relative to P: Look back at the palette data above so you can see the comparison between palette data and the layers.

Under the layers class we have the legend. This tells TB which colours of pixel relate to which layer. The picture is a BIS standard image and is available at: https://community.bistudio.com/wiki/File:SurfaceMapLegend.png.

Note we save that file to the source folder of our project directory and reference it from there. In the colours class we match the RGB values from our mask to our layers so in my case, the sand layer is 255,0,0. Again reference the palette data above to compare the data to see what goes where.

Save the layers.cfg file.

We now need a config.cpp. This is the main section of code used by the game engine to define our world. As with textures and materials, this can be bespoke but would be hugely time consuming and would require knowledge of how the configs are written. I'll provide a more in depth write up on these later, for now we can just borrow one from BIS. Navigate to the map_stratis file in the A3 data and copy config.cpp. Paste it into the root project folder.

Now, the config itself is 5505 lines of code so I won't write it all out here. A lot of the stuff we won't change in this tutorial simply because it gets too in depth. Stuff like weather effects, lighting effects and ILS will be covered in later additions to this tutorial. We do however have to change certain things to make our mod work. Specifically we need to change parts of the config that reference Stratis to suite our own project. So then we need to change:

Line 3 -> Change the class name from A3_Map_Stratis to your project name, in my case this would be GOL_Tutorial
Line 5 -> Put your own name in the string
Line 6 -> Give your map a name
Line 61 -> Change Stratis here to your map name. It's often better to use the same thing throughout to make it easier. Mine then becomes GOL_Tutorial
Line 4655 -> Change the description to something you'll recognise in game. This is what will appear in the editor menu to select the map
Line 4657 -> This is the file that will eventually contain our world data. Change this to suite your project. In my case it becomes GOL_Tutorial\GOL_Tutorial.wrp
Line 5494 -> Change the class name to match the one from Line 3. This is important or the map will not work.

With these parts changed, we finally need to configure our surfaces. We have them linked to rvmats in layers.cfg but the config itself knows nothing about them. At the end of the config add the line:

#include "cfgSurfaces.hpp"

This "header" file will store our surfaces. Go to the root directory of the project and create a text file called cfgSurfaces.hpp changing the file extension won't matter, notepad++ will still open it. We will cover surfaces and clutter in a later addition.

This concludes the config setup for the project.

Clutter and cfgSurfaces

Anyone with a bit of experience in mission making has probably used something called a clutter cutter. This tool is used to clear patches of ground to make things like temporary airstrips or FOBs but what exactly is clutter? Clutter is a collection of randomly generated small objects that the game engine uses to bring your map to life.

The textures we created above, when presented in game, would be simple 2D images. They don't provide any life or vibrancy. Clutter is assigned to each texture via cfgSurfaces to make each patch of terrain look more alive. If, for example, we're walking on grass, we expect to see grass not just a flat image that kind of looks like grass.

CfgSurfaces dictates how each patch of terrain is represented in game. It takes clutter data and texture data then puts it all together to make a surface. Each surface is unique and can be edited to make different sounds, affect movement in different ways and show different clutter. This is what brings the world to life.

To begin with we will configure our clutter. Like any other config in A3, this can be done in the base config.cpp or can be added to a separate file and #included in the base config. This really boils down to personal preference but creating a separate clutter config allows you to keep the base config neat and makes editing the clutter a little easier. For the purposes of this tutorial, we will create a clutter config and some of our own clutter objects.

First things first however, we have a problem. The config.cpp we borrowed from Stratis already has clutter defined in it. Open config.cpp and head to line 63. This should be class defaultclutter. We need to get rid of this but we can also use this as a template for our own clutter config. Create a new text file in your project root directory and call it cfgClutter.hpp. Now go back to our problem section in config.cpp. Cut this line, and the entire class clutter below it. This is a pretty big class, some 400 lines, dynLightMinBrightnessAmbientCoef=0.5 should now be the first line in your world class:

class GOL_Tanith: CAWorld

Paste the data we cut into cfgClutter.hpp. We now have a template for configuring our own clutter values.

Looking down the list then, we see a simple class full of sub-classes. Each sub-class is an individual clutter object. Each object has a certain set of parameters:

class StrBigFallenBranches_pine: DefaultClutter

This looks pretty cryptic to begin with but a little common sense lets you pick it apart. Str is the prefix used for all things Stratis (you may recognise it from our texture work). BigFallenBranches_Pine sounds like it might be a fallen branch from a pine tree, and guess what, it is. The contents of the class define how this will be represented in the game world:

Model = The file path to the p3d model of the object.
AffectedByWind = Defines if the object is affected by the wind. Our tree branch wouldn't be but something like grass would be expected to blow in the breeze. 0 = false, 1 = true.
swLighting = Dictates if the clutter should be coloured by the satellite texture. 0 = false, 1 = true.
scaleMin = The smallest possible scale of the object.
scaleMax = The largest possible scale of the object.

The actual size of the clutter object is a random value between scaleMin and scaleMax.

The values of the objects as they are will be fine for this tutorial. Obviously feel free to play about with them and make yourself some freakishly long grass or whatever you fancy. What do we do if we want to add our own clutter? As long as you have a valid model, simply add the file path in the model field then configure the values accordingly. Using these classes like this, you could add any clutter from any source to your project.

Having our clutter is one thing but as yet the game engine has no idea what to do with it, time to deal with cfgSurfaces. Open the cfgSurfaces.hpp file we created above. As yet this is empty so where do we start? Think back to layers.cfg. Remember this code block:

class Colors

This tells TB where to paint our textures but this isn't entirely true. It tells TB where to paint our SURFACES. The surface includes the texture but also includes other things such as clutter.

In cfgSurfaces then we start building our surface classes. First we need a base class, class CfgSurfaces. Inside this class we have a default class, and we have our custom surface classes:

class CfgSurfaces 
    class Default {};
    class GOL_Tutorial_Sand_Surface : Default
         files = "GOL_Tutorial_Sand_*";
         rough = 0.5;
         maxSpeedCoef = 0.4;
         dust = 0.9;
         soundEnviron = "sand";
         character = "GOL_Tutorial_Sand_Character";
         soundHit = "soft_ground";
         lucidity = 1;
         grassCover = 0.1;

Each surface is named to match the entries in layers.cfg. simply to help keep track of what is going where. Each surface will also contain all of the data in the example above. These settings not only affect the clutter and textures, they affect how the player interacts with the surface:

files = The texture files that relate to the surface. In this case we load all files with GOL_Tutorial_Sand in their name. This is why our texture files all have the same name.
rough = Dictates how rough the surface is. The rougher the surface, the bumpier it is to drive over.
maxSpeedCoef = Dictates how fast you can drive over the surface. Sand for example is quite low while a dirt track would be higher.
dust = Dictates how much dust is kicked up by units moving over the surface.
soundEnviron = Dictates the sound made when a player moves over the surface. A list of available values is available here.
character = This dictates the surface character which we will add later. The surface character class contains our clutter objects. Point to note here, you don't have to add clutter to a surface if you don't want to. If you have a surface like concrete for example, you can use "Empty" here. This means there is no character for this surface and as such, no clutter.
soundHit = Dictates the sound made when a round strikes the surface. A list of available values is available here.
lucidity = Dictates how much light the surface gives off or reflects. Higher values mean brighter lighting and colours.
grassCover = Dictates how much of the surface is covered by grass. Lower values mean less clutter.

We need to produce a surface for each layer we added in layers.cfg. Do this now using the information above to populate your own classes.

With the surfaces done we now need to configure the surface characters. This is done in cfgSurfaces.hpp in a base class called cfgSurfaceCharacters:

class CfgSurfaceCharacters
    class GOL_Tutorial_Sand_Character
        probability[] = { 0.5 };
        names[] = { "GOL_Tutorial_Sand_grass" };
    class GOL_Tutorial_dry_grass_Character
        probability[] = {0.2,0.2,0.2,0.2,0.1};
        names[] = {"GOL_Tutorial_c_Flower_BrushMedium_Blue","GOL_Tutorial_c_Grass_BrushHigh_Dry","GOL_Tutorial_c_GrassLong_DryBunch","GOL_Tutorial_c_StrGrassDryMedium_group","GOL_Tutorial_c_Thistle_Small_GreenYellow"};

The name of these classes is the name used in the character value of the surface. GOL_Tutorial_Sand_Surface for example references GOL_Tutorial_Sand_Character as its character.

Each character class has 2 values passed as arrays. The names array contains the names of all clutter objects used by this surface. These are the class names from CfgClutter.hpp. The probablility array has a numerical value for each of these names. This is important, THE NUMBER OF ENTRIES IN PROBABILITY MUST MATCH THE NUMBER OF ENTRIES IN NAMES. If the total numbers of entries do not match your surface character will be invalid and you won't get clutter.

A second important point here is the values in probablility. These relate to a percentage of the surface that each entry covers and the array position dictates the clutter impacted by the probability. In the above case for example, GOL_Tutorial_c_Flower_BrushMedium_Blue is the first array entry in names so the first array entry in probability, 0.2, is the percentage of the surface that will be covered by GOL_Tutorial_c_Flower_BrushMedium_Blue.

Finally the combined total of the entries in probability MUST NOT BE GREATER THAN 0.99. This is simple maths, if 0.2 is the equivalent of 20% then 0.99 is 99%. Going higher than that will take your total probability higher than 100% and you can't cover more than 100% of an area with something. Again if this is incorrect, you won't get clutter.

Bearing these caveats in mind, you can add whatever clutter you want to the names array. Above I wanted some rough, dune type grass on my sand and as such my sand surface only has 1 clutter object. The dry grass however represents wild growing scrub land and as such has a motley collection of grass, flowers and thistles.

Work your way through your surfaces, filling out the relevant bits you need. Our surfaces are now ready.

The final stage, go back to config.cpp and #include our clutter config:

class GOL_Tanith: CAWorld
    #include "cfgClutter.hpp"                                                                                                                                                                                                              dynLightMinBrightnessAmbientCoef=0.5;

Terrain Builder Part 2

We now have all the parts we need to put this together and get it into game. Open up terrain builder and load your saved project.

We need to import the images we've produced in order to generate our terrain.

Use File->Import to import the terrain (ASC file) satellite image (TX file) terrain normals (TN file) and mask images to the project. SAVE NOW!!

Right click on each new image in the layers manager and select terrain properties. Set the images correctly. The position needs to be 200000E 0N and the map size should be 10240m:


Right click the mapframe in the mapframes window and select properties. We've seen this window before and have configured some of this stuff already. Skip to the processing pane and select the browser button for the layers.cfg. Navigate to your layers.cfg file and select it.

Next hit rebuild terrain which will build the terrain from our heightmap.

Now we configure the imagery. Select to export the satellite texture. Select to export the normals map. Select to export the mask. Set materials per cell to 5 + normals. Select to convert the textures to .paa format and finally hit generate layers:


This can take some time as TB converts our textures for us rather than us doing it manually.

With this done hit file->export->WRP and save it with your project name in the root folder of the project. As an example mine would be GOL_Tutorial.wrp


We're now done with TB and can get to packing the mod ready for game.

Addon Builder

To pack the addon we'll use addon builder from the BIS tools. As was mentioned above, a lot of mod builders will boo and hiss at this screaming "MIKEROS!" from the rooftops but it really is pretty much the same thing.

Open addon builder from the tools menu and set the output directory to somewhere you can remember. For the input directory select the project folder.

Go into options and double check the list of files to skip. If it's empty add:

*.pac;*.paa;*.rtm;*.sqf;*.sqs;*.bikb;*.fsm;*.wss;* .ogg;*.wav;*.fxy;*.csv;*.html;*.lip;*.txt;*.bisurf;*.sqm;*.ext;*.dbf;*.prj;*.shx;*.shp

These files should be copied directly to prevent errors.

With that done go back to the main addon builder screen and hit pack. Once it's finished you now have a PBO of your mod ready in the output directory.

Getting it in game

The final stage to get this into game is to creat a mod folder inside your ARMA 3 installation. Do that now, naming the folder @YourProjectName. Mine for example will be @GOL_Tutorial.

Inside this folder make a folder called addons. Put the PBO we packed above into this folder.

Launch ARMA as normal, making sure you have your mod enabled.

Head to the editor and you should see your island listed. Place a unit and have a look around:

Where to go from here

Obviously there is still a lot of work to be done here. Our map still shows map data from Stratis, we don't have buildings, the ground clutter may not match the textures and the textures themselves may be showing in slightly incorrect places. The bare bones however are there.

I'll be adding to this as time wears on covering everything that will eventually give a full tutorial on terrain production.

Expanding the map - Template Libraries

Our map is all pretty and stuff but it lacks objects. An object on the map can be anything from buildings to trees to piles of trash. A3 has something to the tune of 1000 different individual objects that can be added to the terrain. To add these objects to our map, they must first be referenced correctly. Terrain builder does this through the Template Library system.

Each template is imported from a given directory. Remember when we extracted the game data? This is where it becomes crucial. Every object we reference from the ARMA 3 game data will be referenced from P: so as we import these objects to our templates, they must reference the A3 directory in our P: in order to work properly in game. This does mean however that we can include ANY object from ARMA on our map.

Importing a template is a simple enough process but a vital one. In Terrain Builder look to the left bank of tool windows and you will see the Template Library window. To begin with we need to create a new template. This can be done in one of 2 ways. We can import libraries from other projects but that would be jumping the gun. Assuming then that this is your first project, we need to create a new library from a directory.

This is the button we want:

This will open the Create New Library Dialog:

This dialog lets us define a couple of options for the new template. The first option is the name of the library you want to add. The next options control importing multiple objects from a given directory. If you want to import like this, you must first select the create from directory check button. This will allow you to select the recursive import button. This button will import each sub-directory in the directory you select. This can be useful but can also fill your library with a lot of pointless stuff that you don't need. Next up we can define the fill and outline colours of the objects and the shape. This doesn't change the object in game, rather it is how the object is represented in the 2D editing window of TB.

As an example then, lets say we want some trees. A decent set up for the library to import ourselves some trees would look something like:

You will now see the library in the library manager screen. Inside the library you can see all the objects that belong to that library, in this case, 15 types of tree. Each entry then has a number next to it, and an exclamation mark. These help you track whether or not an object is actually being used in your map or if it is dead weight as it were. The number is the number of the object type currently in use on the map. The exclamation mark is displayed when the number is 0:

Using the above process you can import any object from the vanilla ARMA content. One point to note however, Apex content is still currently under EBO encryption meaning it cannot be used with the official tools as yet. Once an object is imported in this way, it can be used anywhere on your map, as many times as you see fit.

Expanding the map - Forests/Area Fill

A forest in TB is a simple collection of objects from a template library. There is one massive problem with that however, who the hell wants to hand build a forest of potentially thousands of trees?? TB does have a solution to this, area filling of shapes. We simply draw a shape on the map and fill it with randomly selected objects from a list that we define.

To work then. First up we need a new "shape". These shapes exist only in TB and are used to define things such as roads but we can draw any shape we please and use it for a number of tasks. Each shape must be placed in a shape layer. There is no reason why you couldn't put all shapes into one layer but you can have as many layers as you wish for organisation.

To create the layer head to the layers manager window, select the shapes tab then hit the new shape button:

A dialog will open asking for a name so name it something meaningful. Next up head to the Objects tab in the layers manager and repeat the process. This layer holds our objects.

Now we draw the shape that will define the area of our forest. To do this we use the draw polygon tool:

This tool allows you to draw a polygon with as many points or corners as you please. Simply left click on the editing area where you want to lay a point. To finish adding points, double click will link the last point with the first and ends the editing:

With the shape drawn, select the shape then right click it to get the context menu. In the context menu select Fill (Add New Objects):

This opens up the fill dialog. Here we define the list of random objects we want to generate, the density of the placing and a couple of other things. On the top left we have our list of template libraries, you can filter these to narrow your selection. The big window to the right of that shows all the objects in the project that match the filters set in the top left. Below that we have the name for the placement which must be unique. Next up we have object density per hectare. Obviously the higher this number, the more objects will be placed. Be careful not to set this too high otherwise you may crash TB. Better to do multiple runs of a lower number than trying 1 big run or alternately make the placement areas smaller. Clusterisation defines whether or not the objects are clustered together. Increasing these values will give you dense clumps across the area with empty gaps between. Lowering the number will spread everything out more evenly. The Polyline options only apply if you use a polyline instead of a polygon to define the area to be filled. A polyline technically has no width so here you can define a width/radius for the line and dictate whether to place objects too far from the centre. This can be very useful for laying straight lines such as a line of trees lining a road or maybe the lines of crops in a farmers field. With everything set up, hit OK and let it process.

Here's an example:

NOTE: This can take some time so don't worry. Once it's all done, export the WRP, put it in game and go have a look at your handywork.

Real World Geo-Data

As well as making a fictional terrain using L3DT, we can also make a terrain using real world geo-data. Maps such as Altis or Bornholm were made in this way. As with the fictional terrain, we only need a collection of images to make the terrain. The difference lies in how those images are produced.

As we saw in L3DT we need 4 images:
Satellite Texture
Terrain Normals
Mask Image

L3DT produces all of these for us as part of it's procedural generation of the terrain. To make a terrain from geo data however, we need a different method. We will begin by creating the heightfield with a geodata file.

Before we can create anything we need a location, this can be anywhere in the world you please. Altis for example is heavily based on the Greek island of Limnos, an actual island off the eastern coast of Greece. For the purposes of this tutorial we will use Pantelleria, an Italian island in the Strait of Sicily in the Mediterranean Sea, 100 km southwest of Sicily and 60 km east of the Tunisian coast. Pantelleria is roughly 15km x 10km which means it is well within the bounds of the game engine. That's not to say you can't make a bigger island. In theory you can make a map that completely fills a single UTM grid square, an area roughly 800km x 800km. A map this size however would be a huge undertaking. The largest map in A3 at present is Australia which is 40km x 40km. Pantelleria is fine for our purposes here.

Before we can produce any images, we need to know the exact geographic location we want to create. This is where google earth comes in. Using google earth we can pinpoint the specific geographic points that will form the bounds of our map. The map in game must be square so what we want to produce here is a square that encloses the island completely.

Open up google earth and search for Pantelleria, you should end up here:


I've removed the place labels to give a plain image, this will become apparent later. From here we need actual geographic coordinates. We get these from "Placemarks". Google earth uses placemarks to allow you to mark points on the map but the placemark properties also give us our required coordinates. Select placemarks from the toolbar and a new placemark will be added to the centre of the current map view. With the properties page still open, drag the placemark to the top left of the image:


Note I have changed the icon of the placemark and removed the text, again this will become apparent later on. If you look at the properties page you will see we have geographic coordinates for the placemark. In the case above we have 36.861385 Latitude and 11.872033 Longitude. This is our datum point from which we will figure out the other 3. Next up then we need a point 20km East of the datum point, this will be the top right corner. Google earth has a ruler to allow us to measure this distance. Select the ruler and draw a line east from the datum until the distance reads around 20km:


Now, the distance here is approximate as it is very difficult to get an accurate distance. This is not a big deal however as long as the coordinates are accurately noted. The map images can be slightly skewed and compressed later to make the required square shape. With the line drawn, place a second placemark on the map at the end of the line:


Now this will not be perfectly positioned just yet but it does give us the correct distance offset we will need later on. Repeat the process from the datum only this time go south 20km:


We can now take the coordinates of these 3 points and construct our square properly. Our points at present are:

Top Left: 36.861385 LAT 11.872033 LON
Top Right: 36.859463 LAT 12.090487 LON
Bottom Left: 36.684934 LAT 11.874494 LON

We need a square so we must adjust these coordinates slightly. The top left and right should share the same LATITUDE as they should be in line horizontally. Right click the top right placemark and change the latitude value to match the top left. Similarly, the top and bottom left points should share the same LONGITUDE value as they should be in line vertically. The adjusted values then should be:

Top Left: 36.861385 LAT 11.872033 LON
Top Right: 36.861385 LAT 12.090487 LON
Bottom Left: 36.684934 LAT 11.872033 LON

Finally we need a 4th point, the bottom right. This should share its latitude with the bottom left and its longitude with the top right:

Bottom Right: 36.684934 LAT 12.090487 LON

The finished result:


Google earth will save the placemarks automatically for us which is great since we will need them later. For now though we are done with google.

With our coordinates listed, we now need a way of sourcing the geodata at those coordinates. To get this we head over to opentopo. This website allows you to download geodata according to a specified set of coordinates. To get the data for our coordinates then scroll down to the check box that asks to enter the coordinates manually and check it. Then enter the coordinates from our list:


Note we use the Bottom Left and Top Right values only. The Y values are our lat values and the X values are our long values. With the data inputted hit the validate button and you will get something like this:


There's our island. The red box around it marks the area that the geodata will cover. With this done, scroll down to the bottom of the page. Here we set up the options for the geodata download:

Select Geotiff as the output
Uncheck all visualisation options
Enter a job title, it doesn't matter what
Enter a job description it doesn't matter what
Enter your e-mail address


Finally click submit and you'll be taken to the processing page. Let the processing finish and you'll get a screen like this:


Click to download the data and save it somewhere sensible. The downloaded file is double compressed but can be opened easily with 7Zip or something similar. Extract the .tar file then extract again to get output_srtm.tif. This file, a geotif file, contains a grey scale representation of the geographic area we selected. In simpler terms, this is the image that will become our heightfield.

The geotiff file however isn't of any use to us at present, the format simply won't work. To convert it to a usable format, we use QGIS. Opening QGIS is a bit different as there are multiple versions of the program for various uses. Navigate to your QGIS installation folder and select QGIS Desktop with GRASS. This opens the version of QGIS we want. To open the geotiff file, open the folder where you extracted it and drag the tif image into the QGIS desktop. You should get:


To make the tif image usable we must perform a simple function. Right click the output_srtm image in the sidebar and select stretch using current extent:


The image will visibly change. Now we export the image by right clicking the image again and selecting save as. This opens up the export page. On this page select to export as rendered image then select a file location. Obviously make it somewhere sensible:


This image then is ready for editing. We need to edit the file only to turn it into a format ready for terrain builder. We turn then to our old friend the GIMP.

Here we want to make sure the image is useable by terrain builder so we must:
Ensure it is a perfect square of pixels
Export it as a png file

One point to note here on the pixel value. If you think back to the fictional terrain above, the grid size in terrain builder has fixed values. We need our map to suite this to make the terrain easier to build later. To that end we start with a blank image that is of suitable size to hold our image. Our tif image is 788x636 pixels so an overall image size of 1024x1024 will suffice. Next up fill the blank image with full black colour. In our tif file this will be interpreted as 0 elevation:


Next up, import the edited tif file as a layer:


The image contains a lot of black at present, this represents sea. We need to try to get rid of as much of that as possible. We do that by scaling the imported layer. One point to note here, we will distort the image unless we scale with the same pixel ratio. Make sure you lock the ratio prior to scaling otherwise our imagery will be much more difficult to produce later. Scale the image up until one of our dimensions matches the image size:


Re-position the layer so that the island image itself is centralised. Once you are happy with the positioning, merge the layer down to create one single image. Be careful not to snip any of the grey parts of the image as these are the parts that will eventually become land. Once merged, export the image as a png file:


That completes the heightfield. We still need terrain normals, mask and satellite images. The satellite image will form the basis of the others so we will go there next.

Go back into google earth and look closely at the imagery. When zoomed in, this will provide a nice hi-res satellite image. We do however have a problem. If we zoom in, the image will not match the terrain. To remedy this, we must tile the images. How you do this is a matter of personal preference but I will talk through my method.

To make lining up the tiles easier, I make use of the placemarks. We already have the 4 corners marked so if we find the middle point of these values we can quarter the map. For example our lat values are 36.861385 and 36.684934. If we subtract the lower value from the higher we get the difference, 0.176451. We next divide this by 2 to get 0.0882255. Add this to the lower lat value and we get 36.7731595, the exact mid-point between our lat values. Repeat this for the long values and we can draw a grid across our map area, giving 4 distinct quarters:


We can then use the icons of the placemarks as our lining up marks for our tiles. Before that though, we must capture the images. Make sure you adjust the camera to be looking straight down and aligned to north. You should double check this for each image capture to make sure the images will match later on. Zoom in until the four corners of the quarter are visible and the watermark is NOT inside the bounds of the box:


Use print screen then paste the data into GIMP. Select the area of the box making sure to keep the placemarks inside the selection then crop the image to create the tile:


Repeat this process for all the boxes.

Once complete, load the first image into GIMP followed by the second. Make sure to open them as layers so you can move them around. Line up the marks to make the images match up:


Repeat this process to complete the entire image. Once finished, touch up the image by colouring over the placemarks to hide them.

Using quarters gives a mediocre satellite image. To make a true hi-def image, divide the map area further into 8ths or even 16ths. This will obviously take more time but will yield much better results. With the satellite image we can now make the mask image.

If you think back to the fictional terrain, we need a simple RGB colour to represent each patch of ground. We then link this to our textures. Above we worked to a maximum of 5 different colours but this isn't the upper limit. It can work quite well but since we're putting all this effort we may as well cover advanced layering. It is true that you can only have 5 different layers but as we said above, this is per mask tile. We set up the mask tiles in terrain builder during the mapframe creation. Think back to when we set the satellite/surface tile setting. This setting dictates the size of the individual tiles used when producing the surface tiles. The 5 layer rule applies to each of these tiles separately. This means that each layer can have 5 different layers regardless of how many have been used across the map. We do need to be aware of the pixel overlap however. The boundaries between layer tiles will overlap by this margin and any surfaces in this region count toward the 5 limit for BOTH TILES. As long as we bear these points in mind, we can theoretically have as many surfaces as we wish.

To our mask then, we will use the satellite texture as a guide while we manually paint the mask. THIS WILL BE TIME CONSUMING IF YOU WANT A DECENT JOB! There is no way around this this time around. While GIMP can colour exchange the satellite image can have thousands of individually coloured pixels and colour exchange here would not help. Create a new layer over the top of the satellite image. To manually paint then we simply keep a log of the pixel colour value we use and paint the respective area accordingly:


You get the idea. The more effort you put in at this stage, the better looking your map will ultimately be. Furthermore the image above is only 1 tile, the complete satellite texture could well end up being thousands of pixels square. Once done, export the mask layer as it's own image.

Finally we need a terrain normals map. This is surprisingly simple when compared to the above. Simply open the tif png file and run the same normal algorithm we used to produce our own textures. Once converted, simply save it as it's own image.

We now have the 4 images we need to produce a terrain and can proceed to terrain builder just like with a fictional terrain. We may have need to adjust the terrain in buldozer which is covered in the upcoming buldozer section. One final point to note here. When importing the terrain you will import the png file, not an XYZ or ASC.

Exporting Objects from Eden to Terrain Builder

Adding objects one by one in Terrain Builder can be time consuming, difficult and can cause loss of work due to Terrain Builders inherent instability. With the creation of the Eden editor however, we now have the ability to create what we want in the stable game editor and export it to Terrain Builder ready to adjust and bake as needed.

To begin with then you should have your map packed into a mod file and loaded into game. This way you can create missions on it which is what we need. Open the editor and place whatever objects you wish, however you wish:


While you can use any object available in your build of the game, care should be taken when using other mods. If you place an object from another mod, your map will need to have that mod installed in order for your map to work. You will create these "dependencies" automatically and will need to map the mod to your asset library BEFORE you can import the Eden data.

With the objects placed, select Scenario->Export->Export to Terrain Builder:


This will take a little while to process depending on how many objects you have placed. When it is finished, you will get a pop up text box:


This contains the object placement data for EVERYTHING IN THE SCENARIO!

This is important. If you've already built some objects they will also be copied. If this is the case it is recommended that you use the existing objects to help you position the new ones correctly, then copy the new ones into a fresh mission so that you only export what is needed. This saves trying to find the duplicates in TB which can be very difficult and time consuming.

When you have the data for the objects you want, hit the copy button to copy the text to your clipboard. This can then be pasted into any .txt file. Save this text file anywhere you wish.

Open Terrain Builder and open your project. Once loaded go to File->Import->Objects:


This will open a dialog where you can define a file to import, this is your text file. Click the browse button and navigate to the text file you saved above. This will process and position the objects in the file at the stated position and orientation. This is why you must make sure your library contains all the objects first. If there are objects in the file that are not in your library, Terrain Builder will most likely crash and you could well do irreversible damage to your project!

Once the process is complete SAVE YOUR PROJECT!! Remember Terrain Builder is not stable and could crash at any time. You can now open Buldozer and view your handywork:


Chances are some of the objects are slightly out of place. Use Buldozer to position them correctly.

Once done, save your project and export the WRP. The objects will now be present in the game world.

External Resources

Jakerods Atlas: https://forums.bistudio.com/topic/178033-the-atlas-guide-to-arma-3-terrain-making/

This helped me out a lot with TB itself and other stuff like Buldozer. The tutorial is very much "do this coz I said so" but it covers a lot of the bases and is a decent place to start

CapnCaps youtube channel: https://www.youtube.com/watch?v=I1RebMHC1ZM&list=PLUiViqS-dLHq0o7IM7_5u6tCMy-F3CVW6

This sequence of tutorial videos is my go to reference and is especially great if you want to build a real world geo-data map

Goralight, R4IDER, hoofed and 4 others like this

Share this post

Link to post
Share on other sites

Cheers, Jason. The last time I looked into this all the useful guides were in French and they didn't translate very well.

Share this post

Link to post
Share on other sites
9 hours ago, Oksman said:

This shall forever be known as oksmans butthole.

If thats ur butthole I think you should see a doctor asap

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

About us

We enjoy playing ArmA3 in a tactical and professional way and ensuring at the same time a high level of fun is kept within the game. We use tactics and procedures from various armies and modify them to suit our own needs. This allows us to operate in the ArmA 3 platform effectively.

Social Network

Add us on social networks