Connecting terrein nodes

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.

Connecting terrein nodes

Postby diho » Fri Feb 12, 2016 7:12 pm

Hello everyone,

In my own project I needed to connect multiple terrain nodes to each other. In the process of accomplishing this I came across a few difficulties. Luckily I found the solutions, which I now want to share with you.

First of all you need a big heightmap. In this example I am using a heightmap of 512x512. Now you need to split the heightmap in parts. For this example I split it in 2x2 parts. Make sure that the edges of the individual parts that should connect to an other part share one row/column of pixels with it's neighbor. Doing so results in 4 parts of a heightmap with each a size of 257x257 (256 + 1 pixel extra for the shared pixel row/column). Repeat this process for the texture image.

Now you can simply loading the heightmap parts in seperated terrain nodes and align them so they connect to each other.

This will result in the following:

Image

If you look closely, you can see that there are a few gaps at the seams where the terrain nodes connect to each other. This happens when you are at a certain distance to the seam. It is a result of the LOD system of irrlicht. At a certain distance one terrain node has LOD level i, and the one after that will have LOD level i+1 because it has a longer distance to the camera.
The solution to this problem is simply adding two lines to CTerrainSceneNode.cpp around line 640, there you will find the following:

cpp Code: Select all
 
for (s32 j = 0; j < count; ++j)
        {
            if (frustum->getBoundingBox().intersectsWithBox(TerrainData.Patches[j].BoundingBox))
            {
                const f32 distance = cameraPosition.getDistanceFromSQ(TerrainData.Patches[j].Center);
 
                TerrainData.Patches[j].CurrentLOD = 0;
                for (s32 i = TerrainData.MaxLOD - 1; i>0; --i)
                {
                    if (distance >= TerrainData.LODDistanceThreshold[i])
                    {
                        TerrainData.Patches[j].CurrentLOD = i;
                        break;
                    }
                }
            }
            else
            {
                TerrainData.Patches[j].CurrentLOD = -1;
            }
        }
 


These two lines need to be added:

cpp Code: Select all
 
if (j < 16 || j > (count - 16) || j % 16 == 0 || (j % 15) == (floor(j / 15) - 1))
                    continue;
 


resulting in the following code snippet:

cpp Code: Select all
 
for (s32 j = 0; j < count; ++j)
        {
            if (frustum->getBoundingBox().intersectsWithBox(TerrainData.Patches[j].BoundingBox))
            {
                const f32 distance = cameraPosition.getDistanceFromSQ(TerrainData.Patches[j].Center);
 
                TerrainData.Patches[j].CurrentLOD = 0;
                //border patches should be the same
 
                if (j < 16 || j > (count - 16) || j % 16 == 0 || (j % 15) == (floor(j / 15) - 1))
                    continue;
 
                for (s32 i = TerrainData.MaxLOD - 1; i>0; --i)
                {
                    if (distance >= TerrainData.LODDistanceThreshold[i])
                    {
                        TerrainData.Patches[j].CurrentLOD = i;
                        break;
                    }
                }
            }
            else
            {
                TerrainData.Patches[j].CurrentLOD = -1;
            }
        }
 


Compile the engine, compile your code with the new libIrrlicht.a and this will be the result:

Image

Explanation:

We need to make sure that the patches at the borders of terrain nodes all have the same LOD level.

Image

So for j < 16 || j > (count - 16) || j % 16 == 0 || (j % 15) == (floor(j / 15) - 1), where j is the index of an array with patches inside a terrain node.

  • j < 16 selects all the red patches
  • j > (count - 16) selects all the green patches
  • j % 16 == 0 selects all the yellow patches
  • (j % 15) == floor(j / 15) - 1) selects all the blue patches

For making this a complete story, here is the code for achieving this. (with the modified CTerrainSceneNode.cpp). It is a modified version of Terrain Render Example (no. 12). I also added a compiled version for linux users to test.
Please don't comment on the code, I know it can be done much nicer, but it's just for clarity's sake.

https://bitbucket.org/dihomc/irrlicht-connecting-terrain-nodes/src

If you have questions or additions, feel free to ask/comment.

-Diho
diho
 
Posts: 46
Joined: Fri May 20, 2011 9:01 pm
Location: Netherlands

Re: Connecting terrein nodes

Postby christianclavet » Sun Sep 04, 2016 6:47 pm

Thanks Diho! I'll look at this! It may improve the terrain in IRB as we are using a custom terrain node without LOD.
User avatar
christianclavet
 
Posts: 1638
Joined: Mon Apr 30, 2007 3:24 am
Location: Montreal, CANADA


Return to Code Snippets

Who is online

Users browsing this forum: No registered users and 1 guest