Dev Blog
Hi, this is the Stranded III development blog (see also Forum Thread, Comment Thread).
Entry 87 - Terrain LOD, Human, Grass - August 18, 2019
Mesh Terrain Performance
As mentioned previously I built my own mesh terrain!
Here are some cool links which helped me with that:
Creating a grid mesh in Unity: https://catlikecoding.com/unity/tutorials/procedural-grid/
Height calculation: https://ahbejarano.gitbook.io/lwjglgamedev/chapter15 (I boldly stole the method interpolateHeight from there so I didn't have to do the math on my own)
I improved the mesh terrain startup performance by generating the terrain meshes with a delay. So instead of just baking all meshes for all chunks at once on startup I create them in the background while the game is running. This is done with delays to avoid noticeable frame rate drops. Of course the meshes close to the player are created first and the game only starts when the closest meshes are generated.
Chunks very far away from the player are not baked at all until the player comes closer.
Minecraft (and many other games) work the same way. This is why you see terrain parts popping up out of nowhere. Of course it's more beautiful if you hide that effect. Either by building enough terrain chunks before the game starts or by using fog or blur to make it less apparent. I still have to figure out what works best for Stranded III. Probably a combination of both.
I also created a very simple level of detail (LOD) system for my mesh terrain. Instead of 1 mesh per chunk there are actually 3:
LOD0: mesh grid with 1x1 meter sized cells
LOD1: mesh grid with 4x4 meter sized cells
LOD2: mesh grid with 8x8 meter sized cells
So depending on the camera/player distance I show LOD0 (close), LOD1 or LOD2 (far away). Of course the delayed mesh creation explained above also takes the required LOD level into account and creates the related mesh first.
(click for larger version)
A nasty problem when using different LOD levels for terrain chunks are the edges of the chunks. Because of the different LOD levels it is not easily possible to make them fit perfectly together. This can result in ugly holes between the edges.
One solution is to generate the edge areas of a chunk with the precision of the neighbor so they fit togther. But there are two problems with that:
Expensive: More mesh baking is required because changing the LOD of one chunk also affects its neighbors. You would either have to save a lot of edge combinations or create new meshes more frequently (either more memory- or more CPU cost)
Complicated: The required mesh geometry is more complex and pretty difficult/annoying to create in code.
When thinking about a better solution I remembered the terrain system I used with Ogre. It uses a dead simple solution: A mesh strip on the edges which just goes down vertically. That strip simply covers all possible gaps and holes!
You can see the wire frame of it in this video.
I implemented that solution for Stranded III as well.
Cheap: No additional mesh baking / LOD mesh variants with different edges.
Simple: Creating that additional strip geometry in code is quite easy
Wasted render time: Most of the strip geometry is never visible and therefore rendered for no reason. Luckily the strips are quite small in comparison to the rest of the chunks so this is an acceptable drawback
Human Model
Making animal models is tough in my opinion but making humans is even harder. We all are surrounded by humans all the time and we know very well what a human is supposed to look like.
Therefore even the smallest anatomical inaccuracy is recognized. Sometimes you can't tell exactly what's wrong - it just looks weird.
Like with animals I'm going for a low poly and stylized approach. While this makes the process a bit easier the rough body proportions and anatomy still need to be right. Otherwise it looks odd.
I found a nice low poly mal human model on Sketchfab which I'm using as reference.
And this is my progress so far:
(click for larger version)
Like the picture says: This is work in progress. Facial details are missing for reasons. More on that later
Grass
I added grass to my mesh terrain. I'm using Unity's instanced mesh drawing for that.
It allows rendering a big number of meshes efficiently and without creating game objects (which would cause additional performance and memory overhead).
I also found a simple grass shader in the Unity forums.
The grass itself is not casting any shadows (looks bad and costs extra performance). It is affected by light and shadow though (barely visible in the gif). In order to make that work well I had to modify the lighting function in the shader. Otherwise the basic billboard-like geometry of the grass would look really ugly. My modified function only uses the brightness at the vertex position and entirely ignores the normals of the grass mesh. So only the light intensity matters, not the angle.
Also note that all the other plants are not moving yet. This will be added later.
As mentioned previously I built my own mesh terrain!
Here are some cool links which helped me with that:
Creating a grid mesh in Unity: https://catlikecoding.com/unity/tutorials/procedural-grid/
Height calculation: https://ahbejarano.gitbook.io/lwjglgamedev/chapter15 (I boldly stole the method interpolateHeight from there so I didn't have to do the math on my own)
I improved the mesh terrain startup performance by generating the terrain meshes with a delay. So instead of just baking all meshes for all chunks at once on startup I create them in the background while the game is running. This is done with delays to avoid noticeable frame rate drops. Of course the meshes close to the player are created first and the game only starts when the closest meshes are generated.
Chunks very far away from the player are not baked at all until the player comes closer.
Minecraft (and many other games) work the same way. This is why you see terrain parts popping up out of nowhere. Of course it's more beautiful if you hide that effect. Either by building enough terrain chunks before the game starts or by using fog or blur to make it less apparent. I still have to figure out what works best for Stranded III. Probably a combination of both.
I also created a very simple level of detail (LOD) system for my mesh terrain. Instead of 1 mesh per chunk there are actually 3:
LOD0: mesh grid with 1x1 meter sized cells
LOD1: mesh grid with 4x4 meter sized cells
LOD2: mesh grid with 8x8 meter sized cells
So depending on the camera/player distance I show LOD0 (close), LOD1 or LOD2 (far away). Of course the delayed mesh creation explained above also takes the required LOD level into account and creates the related mesh first.
(click for larger version)
A nasty problem when using different LOD levels for terrain chunks are the edges of the chunks. Because of the different LOD levels it is not easily possible to make them fit perfectly together. This can result in ugly holes between the edges.
One solution is to generate the edge areas of a chunk with the precision of the neighbor so they fit togther. But there are two problems with that:
Expensive: More mesh baking is required because changing the LOD of one chunk also affects its neighbors. You would either have to save a lot of edge combinations or create new meshes more frequently (either more memory- or more CPU cost)
Complicated: The required mesh geometry is more complex and pretty difficult/annoying to create in code.
When thinking about a better solution I remembered the terrain system I used with Ogre. It uses a dead simple solution: A mesh strip on the edges which just goes down vertically. That strip simply covers all possible gaps and holes!
You can see the wire frame of it in this video.
I implemented that solution for Stranded III as well.
Cheap: No additional mesh baking / LOD mesh variants with different edges.
Simple: Creating that additional strip geometry in code is quite easy
Wasted render time: Most of the strip geometry is never visible and therefore rendered for no reason. Luckily the strips are quite small in comparison to the rest of the chunks so this is an acceptable drawback
Human Model
Making animal models is tough in my opinion but making humans is even harder. We all are surrounded by humans all the time and we know very well what a human is supposed to look like.
Therefore even the smallest anatomical inaccuracy is recognized. Sometimes you can't tell exactly what's wrong - it just looks weird.
Like with animals I'm going for a low poly and stylized approach. While this makes the process a bit easier the rough body proportions and anatomy still need to be right. Otherwise it looks odd.
I found a nice low poly mal human model on Sketchfab which I'm using as reference.
And this is my progress so far:
(click for larger version)
Like the picture says: This is work in progress. Facial details are missing for reasons. More on that later
Grass
I added grass to my mesh terrain. I'm using Unity's instanced mesh drawing for that.
It allows rendering a big number of meshes efficiently and without creating game objects (which would cause additional performance and memory overhead).
I also found a simple grass shader in the Unity forums.
The grass itself is not casting any shadows (looks bad and costs extra performance). It is affected by light and shadow though (barely visible in the gif). In order to make that work well I had to modify the lighting function in the shader. Otherwise the basic billboard-like geometry of the grass would look really ugly. My modified function only uses the brightness at the vertex position and entirely ignores the normals of the grass mesh. So only the light intensity matters, not the angle.
Also note that all the other plants are not moving yet. This will be added later.