stephen-hqxu / superterrainplus

SuperTerrain+: A real-time procedural 3D infinite terrain engine with geographical features and photorealistic rendering.
MIT License
12 stars 1 forks source link

Implementing Free-slip Hydraulic Erosion #15

Closed stephen-hqxu closed 3 years ago

stephen-hqxu commented 3 years ago

This pull request deems to officially resolve #1.

Free-slip hydraulic erosion is a technique, that allows out-of-chunk-boundary raindrop to "free-slip" to neighbour chunks instead of ending the lifetime early. This significantly improve eroding efficiency of every raindrop and gets the same erosion detail as of previous algorithm with fewer number of erosion iterations.

Approximately 20k iterations now gives same LoD as 80k iterations before.

Main academic reference: Ondˇrej Št’ava, Bedˇrich Beneš, Matthew Brisbin, Jaroslav Kˇrivánek: Interactive Terrain Modeling Using Hydraulic Erosion. In Eurographics/ACM SIGGRAPH Symposium on Computer Animation (2008)

Boundary conditions are implemented using so called ghost cells that contain a copy of their neighbors and act as a free-slip boundary where no water can run out of the simulation domain. However, water movement along the border is not restricted.

Checklist

Main free-slip hydraulic erosion feature

Releated improvements addressed in this release

stephen-hqxu commented 3 years ago

How it works

The main idea is requesting all adjacent chunks of the current chunk we are working on, make a copy of them and combine all chunks into a large texture, erode them as usual, break the large texture back to chunks and finally store them back.

Data safety is guaranteed. Chunks have been copied must not be used by any other threads until they are returned and released, it can be achieved by a simple lock.

There are 2 main technical difficulties:

  1. When combining all neighbour chunks into a large texture, the index used to reference this texture is different from the one used when they are separate. In other words, this is the difference between first index in chunk i = last index in chunk (i-1) + 1 and first index in chunk i = 0.
  2. Prior to erosion, heightmap generator deliberately offsets index by 1 to make sure the value at the edge of this chunk is the same as the adjacent's, so two disconnected meshes don't leave any seam. Yet after erosion it's no longer guaranteed, we need to manually normalise the pixel at the edge to align them such that the terrain becomes seamless. How to interpolation edges for the best performance is challenging.

A brief comparison

Figure 1: Showed erosion

comparison1

Figure 2: Showed deposition

comparison2