A tool to generate terrain meshes from heightmaps. Using a .bmp file, apply a height offset to a plane that can be exported as a .fbx file.
Role: Programmer
Team: 1
Timeframe: 6 weeks
Engine: WPF (C#)
Select a .bmp file to use as the heightmap for an explorer popup window. Select properties for the scale (x and y axis), strength (height offset multiplier), and resolution scale (number of vertices within a model). The heightmap is stretched to the scale of the mesh, with the colour of the pixel at each vertex being used as the height. The mesh is created in an .fbx file and saved a selected file location.
Mesh generation is completed in stages.
The first stage is generating vertices. This uses the x and y scale, and creates that number of points in the negative and positive scale of each axis. The number of vertices is multiplied by the resolution - a scale of 128x128 and a resolution of 2.0 would have points:
-128.0, -127.5, -127.0, ..., -0.5, 0.0, 0.5, ..., 127.0, 127.5, 128.0.
The vertices are then used to create faces. Faces are triangles using three vertices as the points. Pairs of faces are created using squares of vertices, where two of the three points of the triangle are shared.
Smooth normals are generated based on the face data. Normalising the cross product of two edges of the triangle gives a vector pointing away from the surface of the triangle. Each vertex accumulates the normals for each face for which it is used. Once all faces are used, the accumulated normals for each vertex are again normalised to create a smooth normal.
Texture coordinates map to each vertex in the mesh. There is one UV for each vertex.
On completion of generation, all data is stored in a file. Each line is prefixed with the type of data it is.
'v' - Vertex
'vt' - Texture Coordinate
'vn' - Normal
'f' - Face
A simple user interface created with WPF. I used a simple MVVM architecture, creating a basic relay system. This allows for decoupling the UI and the backend functionality. While pre-built systems exist as plugins I could have used for this to reduce workload, I felt it important to create this from scratch to better understand how to properly use the architecture in future, larger projects.