Terrain Rendering

Flight sim and terrain render
Flight simulator to navigate around the terrain

Using the Vulkan API I explored some of the ways terrain is rendered and implemented some optimisations techniques. The terrain is generated by reading values from a gray-scale height map image and using them as the Y value of vertices of a grid in the XZ plane.

The need to send vertex attribute data to the GPU can be bypassed completely by invoking VkCmdDraw or VkCmdDrawIndexed without binding a vertex buffer. Vertex data is generated in the vertex shader by using gl_VertexIndex and some information on the terrain grid dimensions:

int id = gl_VertexIndex
int row = id / mapSize;
int col = id / mapSize;
vec2 uv = vec2(row / (float)mapSize, col / (float)mapSize);
vec3 position = vec3(
  row - mapSize / 2.0f,
  texture(heightSampler, uv),
  col - mapSize / 2.0f);

A typical optimisation for terrain rendering is to apply binning to the terrain, i.e separating sections of it into bins, and only rendering those currently visible to the camera. I opted to divide the terrain into regular sections and use the computed dot product of the bin’s midpoint with the camera’s view direction to determine if it is in view or not.

Terrain binning
Terrain bins culled based on view direction

There are many other ways to optimise terrain rendering such as by using different terrain data structures like kd-trees or dynamic tesselation on the GPU for LODs. I hope to revisit this project and explore more terrain rendering techniques with my improved C++ and Vulkan knowledge.