Terrain Editor

Terrain Editor Screenshot

A stand-alone terrain editor for Windows created using C++ and DirectX. If you find this terrain editor useful or have any queries/comments regarding the editor please feel free to leave a comment or send me a message using the contact form.

Overview
Features
User Guide
Screenshots
Downloads
Using An Exported Terrain
Notes

Overview

Stand alone Terrain Editor for Windows created using C++, DirectX9 and the HLSL (High Level Shading Language).

This project makes extensive use of the Operating System Manager Library.

Features

  • Create terrain
  • Manually edit terrain
  • Manually texture terrain
  • Automatic terrain generation/manipulation through the use of algorithms
  • Automatic terrain texturing through the use of a default or user defined algorithm
  • Save terrains for further editing later
  • Export terrains to a .X file, a colourmap, and an information file

User Guide

Loading The Terrain Editor
Creating A New Terrain
Loading An Existing Terrain
The Terrain Dialog
Saving A Terrain
Changing The Skybox
Exiting The Terrain Editor

Loading The Terrain Editor

Once the editor has been launched you will be asked to select a resolution to run the editor in, only supported resolutions will be shown.

Screen Options Dialog

Screen Options Dialog

Expanded Screen Options Dialog

Expanded Screen Options Dialog

Once a resolution has been selected you will be asked if you want to create a new terrain or load an existing terrain.

Terrain Creation Dialog

Terrain Creation Dialog

Creating A New Terrain

After selecting to create a new terrain you will be asked to specify the dimensions of the terrain.

Terrain Dimensions Dialog

Terrain Dimensions Dialog

The first combo box determines the size and detail of the terrain, the sizes listed represent the number of vertices per row and column. The second combo box determines the spacing in-between each row and column (the space between vertices on the terrain).

Loading An Existing Terrain

After selecting to load an existing terrain you will be presented with a file selection dialog and asked to select the terrain you wish to load.

Terrain Load Dialog

Terrain Load Dialog

NOTE: all three terrain files must be in the same directory.
NOTE: only terrains created with this editor may be loaded as each terrain requires three files. The .X model file, the colourmap and the terrain information file.

The Terrain Dialog

The Terrain Dialog

The Terrain Dialog

Buttons

‘Change Sky Texture’ opens up a file load dialog allowing you to select a new skybox to use see Changing The Skybox for more information.

‘Save’ brings up a save file dialog allowing you to save the terrain. The only thing that will not be saved is the texture assignment e.g. what texture was texture 1(2,3,4) although the placements of the textures will be saved in the colourmap.

‘Exit’ brings up a confirmation dialog asking you if you are sure you want to exit and reminding you that any unsaved changes will be lost.

Height/Texture Mode

Height Mode

‘Cursor Mode’ a default mode that allows you to click on the terrain and have no changes made (useful for navigating around the terrain).

‘Increase Height’ when the terrain is clicked the vertices inside the terrain cursor will increase in height with the vertices in the centre of the terrain increasing in height more than the ones near the edge of the cursor. The amount of displacement is determined by the ‘Cursor Force’ slider bar in the ‘Cursor Options’ section.

‘Decrease Height’ same as ‘Increase Height’ above but decreases the height of the vertices.

‘Smooth Terrain’ when clicked on the terrain the vertices inside the terrain cursor are smoothed out. (Useful for removing jagged/rough areas of terrain).

‘Flatten Terrain’ when clicked on the terrain the vertices inside the terrain cursor are flattened (their height is set to 0).

Texture Mode

‘Current’ this is a vertical stack of radio buttons indicating which texture is currently selected (1,2,3,4 or remove).

‘Texture 1(2,3,4)’ the combo box next to each contains a list of each loaded texture available for ‘painting’ on the terrain. Note that painted textures are categorised as texture 1, texture 2, texture 3 and texture 4 not any specific texture.

‘Number Of Repeats’ each texture has one of these slider bars. This represents the number of times a texture would be repeated across the entire terrain.

‘Load New Texture’ brings up a file load dialog allowing a texture to be loaded. Once a texture is loaded it is added to each combo box.

Cursor Options

‘Cursor Size’ slider bar that controls the area of terrain that the terrain cursor covers.

‘Cursor Force’ slider bar that controls the amount of change for each height or texture operation. E.g. the displacement on a height alteration.

Rendering Options

‘Render Terrain’ renders the terrain as solid textured geometry.

‘Render Terrain With Wireframe’ same as above but with a wireframe rendering on top.

‘Render Only Wireframe’ renders only the terrain wireframe.

‘Light Direction X(Y,Z)’ controls the direction of the directional light on each axis (useful to see the terrain under different lighting conditions).

Terrain Generation Algorithms

For a description of each algorithm and what effects it has please look at the terrain algorithms page.

‘Random Terrain Generation’ selects random amounts of iterations for all of the algorithms.

Terrain Texturing Algorithms

There are two main rules in this section, the height rules on the left and the slope rules on the right.

The height rules dictate which texture starts and ends at what height. Any overlap between the start of one texture and the end of another will result in a smooth blend between the textures.

The first slope rule takes in a maximum height for the rule, this is the slope in degrees that the terrain has to be greater than for the rule to take effect and which texture should be used for this rule.

The second slope rule is exactly the same as the first slope rule except instead of using a maximum height for the rule, it uses a minimum height.

The texture terrain button will use these rules to automatically texture the terrain. (You will still have to select a texture to use for texture 1,2,3,4 to see the results of this algorithm.)

Saving A Terrain

To save a terrain just click the save button at the bottom of the terrain dialog. This will bring up the save file dialog.

Terrain Save Dialog

Terrain Save Dialog

Changing The Skybox

To change the skybox just click the ‘Change Sky’ button at the bottom of the terrain dialog. This will bring up an open file dialog asking you to select the skybox you wish to use.

Exiting The Terrain Editor

To exit the terrain editor either click the ‘x’ button located in the top right corner of the terrain editor or select the ‘Exit’ button located at the bottom of the terrain dialog.

You will be asked to confirm the exit of the terrain editor to give users the chance to save any work before exiting.

Screenshots

Terrain Editor Screenshot 1

Terrain Editor Screenshot 1

Terrain Editor Screenshot 2

Terrain Editor Screenshot 2

Terrain Editor Screenshot 3

Terrain Editor Screenshot 3

Downloads

Terrain Editor application (82.9 MB zip file)
Terrain Editor source code (256 MB zip file)
I know the zip files are quite large so I have included the same content below as rar files.
Terrain Editor application (53.6 MB rar file)
Terrain Editor source code (166 MB rar file)

Using An Exported Terrain

The .X file terrain model is created in a regular grid format. The .X file can be loaded using a model loading library, custom model loading code or by using DirectX (in version 9) via the D3DXLoadMeshFromX function.

The terrain is created around the point 0,0,0 however as the minimum height of a point on the terrain should be 0 when the terrain is saved the terrain is re-centered around the point 0, maximumHeightPoint/2, 0.

The code used to create the terrain grid:

void Terrain::GenerateTriangleGrid(int vertsPerRow, int vertsPerCol, int cellSize, std::vector &verts, std::vector &indices) const
{
    //Calculate the required information
    int numVerts = vertsPerRow * vertsPerCol;
    int numCellRows = vertsPerRow - 1;
    int numCellCols = vertsPerCol - 1;
    int numTris = numCellRows * numCellCols * 2;
    int width = numCellCols * cellSize;
    int depth = numCellRows * cellSize;

    //Resize the vertex and index vectors
    verts.resize(numVerts);
    indices.resize(numTris * 3);

    //Calculate the center of the terrain
    float xOffset = -width * 0.5f;
    float zOffset = depth * 0.5f;

    //Just a counter
    int k = 0;
    //Calculate the vertices
    for(float i = 0; i < vertsPerRow; ++i)
    {
        for(float j = 0; j < vertsPerCol; ++j)
        {
            verts[k].x = j * cellSize + xOffset;
            verts[k].y = 0.0f;
            verts[k].z = -i * cellSize + zOffset;

            //Increase the counter
            ++k;
        }
    }

    //Reset the counter
    k = 0;
    //Calculate the indices
    for(DWORD i = 0; i < static_cast(numCellRows); ++i)
    {
        for(DWORD j = 0; j < static_cast(numCellCols); ++j)
        {
            //Calculate the first triangle
            indices[k]     =   i   * vertsPerCol + j;
            indices[k + 1] =   i   * vertsPerCol + j + 1;
            indices[k + 2] = (i+1) * vertsPerCol + j;
            //Calculate the second triangle
            indices[k + 3] = (i+1) * vertsPerCol + j;
            indices[k + 4] =   i   * vertsPerCol + j + 1;
            indices[k + 5] = (i+1) * vertsPerCol + j + 1;
            //Increment the counter on a per index basis
            k += 6;
        }
    }
}

The code used to access a specific vertex on the terrain:

//Lock vertex buffer
VertexPNT* v = 0;
if(! CheckHR(m_mesh->LockVertexBuffer(0, (void**)&v))) return false;
//z is the row you wish to access and x is the column you wish to access
float height = v[z * m_numVertsPerRow + x].pos.y;
//Unlock vertex buffer
if(! CheckHR(m_mesh->UnlockVertexBuffer())) return false;

The vertex deceleration used for the terrain:

/**
*\struct VertexPNT
*\brief Stores the Position, Normal and Texture Co-ordinates of a vertex
*/
struct VertexPNT
{
    VertexPNT() : pos(0.0f, 0.0f, 0.0f), normal(0.0f, 0.0f, 0.0f), tex0(0.0f, 0.0f) {}
    VertexPNT(float x, float y, float z, float nx, float ny, float nz, float u, float v) : pos(x,y,z), normal(nx,ny,nz), tex0(u,v) {}
    VertexPNT(const D3DXVECTOR3& v, const D3DXVECTOR3& n, const D3DXVECTOR2& uv) : pos(v), normal(n), tex0(uv) {}

    /** Holds the position of the vertex. */
    D3DXVECTOR3 pos;
    /** Holds the normal of the vertex. */
    D3DXVECTOR3 normal;
    /** Holds the texture coordinate of the vertex. */
    D3DXVECTOR2 tex0;
    /** Holds the vertex delceration for the vertex. */
    static IDirect3DVertexDeclaration9* Decl;
};

The code to initialise the vertex layout:

bool InitialiseVertexDeclerations(IDirect3DDevice9* device)
{
    //The layout in memory of the vertex decleration
    D3DVERTEXELEMENT9 VertexPNTElements[] =
    {
        {0, 0,  D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
        {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
        {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
        D3DDECL_END()
    };
    //Register the decleration with directX
    if(! CheckHR(device->CreateVertexDeclaration(VertexPNTElements, &VertexPNT::Decl))) return false;

    return true;
}

The colourmap (.png) is a regular colourmap with the red channel used to represent the weighting of texture 1, green to represent the weighting of texture 2, blue to represent the weighting of texture 3 and alpha to represent the weighting of texture 4. Each texel in the colourmap represents a vertex on the terrain.

Notes

Terrain Textures

The textures located in the Terrain Editor/Textures folder (Dirt.png, Grass.png, Rock.png, Snow.png) are property of Spiral Graphics Inc. These textures were obtained from their Genetica Texture Packs and exported to png using their Genetica Viewer.

Jul30

Leave a Reply