Skip to content

Base concept

mohsenph69 edited this page Aug 10, 2023 · 12 revisions

Base concept

So we start from simple concept and as we go further we add more and more.

The base of the Terrain is made of Terrain chunks, the bellow image is an example of 3 Terrain chunk terrain_chunks

The left chunk is the chunk with higher resolution which is used in area closer to the camera, the right chunk is the chunk that is used in area further away from player, and the middle chunk is the chink that connect two LOD so there will be no gap in Terrain, Please look at the image above and process how this chunk system works. also for connecting LOD in other direction like top, bottom ... we should remove the correct vertices. At the end you should not worried about the connecting two LOD because the plugin do all the work automatically.

terrain chunk features

We divide the terrain to these pieces, and now let us categorize terrain chunk, There are two important factor that determine what kind of chunk we have.

  • the vertex amount of the chunk
  • the size of the chunk

For example in the above image we have 5 vertices and 4 edges in each direction for LOD0 (I mean width and height)! and please note always the number of vertices is one more than the number of edges! The total number of vertices in LOD0 is 25 and the total number of the vertices in LOD1 is 9, So you can see the vertex count between two LOD is changing exponentially, So consider this that LOD setting in terrain can affect a lot your performance.

Now let's talk about the size of the terrain chunk, the size of each terrain chunk can be any number in power of two, For example in above image the distance between two vertices can be 0.25, 0.5, 1, 2, 4, 8, ..., The this distance is always in multiplication of number two, and also the width of the terrain chunk is like this, 8, 16, 32, 64, 128, ...! So The width of the chunk is also in power of two. Please take a look at terrain chunk and if it is necessary take a paper and draw some terrain chunk so you understand this concept well

So in above image if the distance between two vertices in LOD0 is 4, the distance between vertices in LOD1 is 8! But for now the width of two LOD is same

Congratulation the first part is done I hope everything is clear up to this point

Divide the terrain to a grid of chunks

Now that we know how terrain chunks work let's divide the terrain and create our terrain from these chunks! We create a imaginary grid and then we put terrain chunk inside that imaginary grid

terrain_grid

Now depend on how much faraway from camera is the grid cell we set the correct terrain chunk LOD to that.

Grid features

So there are some factor in our grid that determine the structure of our grid, I will write them down here:

  • grid cell width: is the width of each cell in the grid in meter, This will determine the grid unit, and you can change that too, if you worked with TileMap in Godot, This is same as tile-size
  • Min horizontal scale: So we put the terrain chunk inside each cell of our grid, But the closest chunk to the camera, how much vertex in each direction it has, it has 1 vertex for each meter or 2, 4, 8, ...!
  • Max horizontal scale: So you know as we go further away from the camera the terrain chunk LOD will decrease, but what is the maximum vertex per meter should have the lowest resolution terrain chunk 16, 32, 64, ...! But one important thing to consider is that Max horizontal scale can not be bigger than the size of the grid cell width, because in that case we can not fit the terrain chunk inside grid.

The result of two base concept above

So by applying only the two concept above you can create a simple terrain. Also this terrain can have different grid cell width also you can adjust different level of detail into that terrain by a little programming. And that was the first step I made for creating the terrain and after that I just add more and more optimization to terrain.

This is the first video which I made and I apply these two concept to create a terrain and on that time I just made that with GDScript

https://www.youtube.com/watch?v=9olfCkPs1WU

And You can made a terrain like image bellow with these two concept

03

So now we create a simple terrain with two concept of grid and terrain chunk, These two thing are really simple concept but try to understand them well

Optimization

So the terrain above is good for small scale but it has a problem for big scale terrain which I will tell you later.

First let me ask this question, Why we divide terrain to chunks?

We did that for two reason:

  • First we are able to make different level of detail on terrain, so the number of the vertices will decrease further away from camera
  • Second we do that so the area which are not visible on camera will be culled and not shown, Godot has a automatic culling system which remove the meshes which are not in camera frustum, so GPU will not draw them, You can see this concept in image bellow

camera_frustum_s

In image above the part which are in green is shown and the part in red are the part which is culled and not shown!

Problem with large scale terrain

The main problem of this method with large scale terrain is the number of the terrain chunks, imagine terrain chunk width is 32 meter and we want to create a 16km by 16km terrain we need 262,144 terrain chunk to make this terrain. Our CPU can not handle to cull and process this amount of terrain chunk, and we need to find a solution to this problem!

Before I tell you my solution for this take a look at the image bellow and compare that to previous image

cam_f

Can you see that?! The terrain chunk which are further away from camera don't need to be small be be culled! So we should find a way to make those chunks further away from camera bigger, But we should also keep the first two basic concept of our terrain!

Merge Terrain chunks

My Idea for making the terrain chunk was to merge the terrain chunk further away from camera, When I successfully apllied this method I made a video on youtube which you can watch that with this link:

https://www.youtube.com/watch?v=Z8wHAa4RvxE

So look at the image bellow. This is our terrain shown in a different way, the number 4 represent **LOD 4 **and number 3 represent the LOD 3

Grid_lod

So we can merge some of the LOD also with keeping the two first base concept of our terrain, I colored the part which we can merge!

colored_merged

I really recommend to watch the video which I put the link of that above, But the final result of merge is this:

merge_result

Finishing the merge algorithm for me was one of the biggest step which I made, I achieve this with a lot of try and error! in image above each number represent the level of detail, You can see part of the terrain which are closer to camera has much smaller terrain chunk size and as we go further the size of the terrain chunk will increase. This reduce a lot the amount of the terrain chunks!

But this optimization is not enough!!!!!!!

Divide Terrain to regions

For now we solve the problem with the culling system and the number of the chunks, But for real terrain we need to apply a height-map texture to it, and move the vertices, of our terrain base on that height-map texture.

For small scale we don't have problem, but if the scale of the terrain get bigger and bigger that Height-map texture become huge, and at some point it will occupy a large amount of our GPU memory! And for Open-world games which we need a lot of asset with texture, this can cause GPU memory problem for us!

So what we can do about this?

Up to this point you know the terrain which are further away from camera have less number of vertices, So if they have less number of the vertices why we don't put a lower resolution height-map texture to them!!!!

Maybe there are many way to accomplish this but I choose this way. I divide the terrain into different regions, Each region has a different material with different height-map texture!

terrain_regions

After that I reduce the number of pixels for region further away from camera!!!

But Please note you can not simply reduce the number of height-map texture pixels by resizing that image, This is a terrain and between each region at edges we should have the same pixel, otherwise there will be a gap in terrain, So a special algorithm needed to resize height-map Texture

We apply the same thing to normals texture and any other optional texture which is huge and can take a lot of space on GPU like splat-map

Normals also usually can be created in Shader, But in this case as we divide the terrain we can not calculate normals in shader because in edge of the region we can not calculate normals, But that is not a bad thing, because we reduce a lot of GPU computation

So what we did in this part is this: We put the huge images like height-map and normals in RAM memory, and as we stream these texture to GPU memory, depend on what resolution we need at that moment! (I can say we sacrifice the RAM memory for sake of GPU memory)

The result was amazing

After applying this I got a amazing result, in a 16km by 16km terrain, the amount of the GPU memory usage for height-map and **normals **change between 4MB up to 60MB, But that depend on how you set your LOD setting if the terrain further away have higher density of vertices they will have higher heightmap resolution!

You can see the result in this video: https://www.youtube.com/watch?v=ZUXAuhoPV5k

The effect of dividing terrain to regions on merging algorithm

As we use different materiel for each region we can not merge terrain chunk bigger than the region size, or in another word we can not have a chunk which part of it is in one region and part of it is in another region. The terrain plugin automatically prevent to merge between regions but this is a good thing to know about.

Very Good you finish the first part, Try to understand this part very good before going further, To understand them well try to watch those video link in this page