Hello Unity fans and welcome back to my game development series. In the last video we started adding a performant mini-map to the game. I wanted something that would take a negligible amount of system resources, while still looking good and being functional. As part of these efforts I have also been studying up on and testing optimisation. Remember that this is really my very first game development experience, so there are lots of knowledge and many techniques to consider as I’m progressing and learning. More experienced developers will no doubt be able to identify bad ways of doing things in my previous and future videos, but I do feel the last few weeks of considering optimisation has awarded me with an enormous amount of very impactful knowledge. It has been mind-blowing to see how much one small factor can drag down, or improve, the frame rate. In the next few videos, I’ll be discussing some of those factors, kicking off with dynamically creating LODs, or levels of detail, for the randomly created terrain meshes themselves.
While more and more triangles are needed to create smoother and more detailed models, that comes at a system resource cost. Triangulating and displaying detailed terrain takes a lot longer than triangulating and displaying more elementary terrain. Where our terrain contains terraces and cliffs, and in combination with the randomness we’re adding to make the terrain less monotone, considerably more triangles are required to draw the terrain. But when these more detailed hexes are far away in the distance, most of that detail is all but indistinguishable from more elementary triangulations. This means that we could display less detailed versions of this terrain in these cases.
Unity allows us to implement a Level of Detail, or LOD, system quite easily. By creating a LOD group, setting up its parameters and specifying the different meshes to be displayed by each LOD, Unity automatically handles switching between the LODs based on the relative size of the meshes on the screen. The quality settings also contain an overall multiplier for LOD distances, so all LODs can be adjusted at once to switch at larger or smaller relative sizes.
To implement this system into our terrain meshes, we add an array of LOD transitions to our mesh. Whenever this array isn’t empty, we create LOD versions of our mesh’s vertices, cell indices, cell weights, UVs and triangles. We will use these exactly like we did for the main mesh – they will just contain much simpler meshes. Next, we set up the material and create a LOD group with settings indicating we don’t want fading between the LODs. We’ll actually only use one extra LOD level, but the script is written to be able to handle more. So, for each LOD level, we set up a mesh, its renderer and LOD options. When everything is set up, we apply the LOD group.
Next, throughout the HexMesh script, we now add the same functionality for the new LODs as we had for the main mesh. This includes setting up the Listpools, applying them and adding triangles, quads, UV and cell data to them. All that remains now is populating these meshes, although this is the most difficult part. The terrain gets triangulated in the HexGridChunk script. For all the different possible configurations for triangulating a hex, a less detailed version needs to also be triangulated in the LOD mesh. For examples of how this was done for the Minimap, which can be even less detailed, check out the video linked to in the top-right. We apply the same idea here.
For example, in the detailed version we’ve split each segment’s edge fan into 4 triangles, to give the edges some variability. However, at distance, we don’t have to divide the segment fan into 4 different triangles, since we don’t need the variation, so we can use one triangle only. The same goes for cliffs and terraces. We could use a single cliff face per cliff, and even replace the terraces by cliff faces only, since the terraces aren’t required at distance. However, you would have noticed that we sometimes do have to triangulate what I call the HD version of the terrain, even in the lower detail LOD. But why? Well, each chunk decides which level of detail it should be displaying depending on its relative size on screen. However, if low-detail hexes on the edge of one chunk have to connect to high-detail hexes on the edge of the neighbouring chunk, there are slight gaps in the terrain. For example, you’d be trying to connect a segment’s edge fan consisting of a single triangle to one consisting of 4 triangles, leaving some gaps where the detailed edge fan contains variability. And it becomes even worse where cliffs and terraces are involved, where the edges can become quite detailed.