Terrain Rendering
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.
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.