Discontinuity glitch between neighboring terrains

There are very few posts discussing about multiple terrains neighboring each other (e.g. a very old post).


Now I am trying to make two terrains adjacent to each other.
I found there are very small glitches (narrow gaps) at the boundary.
For example:


I don’t think it’s a simple shift due to wrong coordinates.
If set camera to FILL_WIREFRAME mode


I also noticed the mesh seems not continuous.


My sample code:

 Node* terrain_node_center = scene_->CreateChild("TerrainCenter");
  Terrain* terrain_center = terrain_node_center->CreateComponent<Terrain>();

  const float size = 204.8;
  Node* terrain_node_east = scene_->CreateChild("TerrainEast");
  terrain_node_east->SetPosition(Vector3(size, 0, 0));
  Terrain* terrain_east = terrain_node_east->CreateComponent<Terrain>();

  Node* terrain_node_west = scene_->CreateChild("TerrainWest");
  terrain_node_west->SetPosition(Vector3(-size, 0, 0));
  Terrain* terrain_west = terrain_node_west->CreateComponent<Terrain>();

  Node* terrain_node_north = scene_->CreateChild("TerrainNorth");
  terrain_node_north->SetPosition(Vector3(0, 0, size));
  Terrain* terrain_north = terrain_node_north->CreateComponent<Terrain>();

  Node* terrain_node_south = scene_->CreateChild("TerrainSouth");
  terrain_node_south->SetPosition(Vector3(0, 0, -size));
  Terrain* terrain_south = terrain_node_south->CreateComponent<Terrain>();

  std::vector<Terrain*> terrains{terrain_center, terrain_east, terrain_west, terrain_north, terrain_south};
  for (auto* terrain : terrains) {
    terrain->SetSpacing(Vector3(0.1, 0.2, 0.1));

//    terrain->SetMaterial(cache->GetResource<Material>("Materials/Terrain.xml"));


 // I tried both setting and not setting neighbor, no difference.



My heightmap is 2049*2049 (2^n + 1).
I also made sure the edge pixels of two images are the same (e.g. 2049 pixel for 2048 size).
Also attached example heightmaps:


Any help?

I’m not sure that “smoothing” was ever tested with neighbor terrains. Use it at your own risk.

hmm… that explains it.
No glitch when I disable the smoothing.
Any plan to support that?

Terrain supports heightmaps that encode height in the Red and Green channels (whole part in red, fractional in green). If you use this type of heightmap, smoothing is not necessary and it should work with neighbor terrains. Otherwise, you would need to write your own smoothing code that is ‘aware’ of the neighboring terrains, in order to correctly smooth across boundaries.

How do you export those channels with stuff like WorldMachine?

Not sure since I dont use World Machine, but I suspect it can export 16 bit PNGs. While Urho can’t import 16 bit PNG, you could maybe write a converter to take the R channel and split it into 8bit R and G channels.

I played with 16 bit heightmap a little bit, somehow I found the smoothing is still valuable given my original heightmap data has 1 meter resolution with 0 ~ 7k meter range. I could use 3rd party tools to refine that heightmap but that would be another topic.

Anyway, I was thinking to write a custom Terrain class for my own use. For example, I need the terrain on a spherical surface, but not the whole planet. So it’s easier, I can just map from 2D coordinates into curved surface if I only need a small part on that spherical surface.

The best plan for me is: keep the whole Urho folder untouched, so I can check in newest repo easily. Then have a folder for all my own custom classes.

Now my question is: what is the best practice to write our own custom components?

  • I could directly inherent from Component can duplicate most code from Terrain class, which I don’t like.
  • Or I can inherent from Terrain class but I need to change the private section into protected. By the way, why most classes in Urho are using private instead of protected, to avoid inherent?

I can’t answer for “best practice”, but I can say that this is what I would do:

Specifically, I’d copy the Terrain.{cpp,h} files, then refactor (or just find and replace) all Terrain references to SphereTerrain, then modify the class as needed. This was the route I took when I needed some extra features for particle effects, but I’ll probably switch to Spark or Effekseer rather than finishing what I was working on.

If you want to go the other route, remember that you’d also probably need to make some additional methods virtual. And if there was no particular reason for forbidding such inheritance (I can’t tell you either way), then I’d add that a PR would always be welcome!