Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

River system for procedural terrain

Discussion in 'Scripting' started by MakakWasTaken, Oct 9, 2015.

  1. MakakWasTaken

    MakakWasTaken

    Joined:
    Mar 26, 2015
    Posts:
    45
    I have been trying to create a procedurally river system, but I haven't quite figured out a good solution yet.

    I could try the standard one with having a water plane at a certain level and then just modify the terrain where I wanted it to. But I want it to be a little more advanced, I want the rivers to run down the sides of my mountains and then become a waterfall if it gets too steep. I have figured the waterfall part out, I just need to find out how to create the river system, and then implement it. I have tried to make a copy of the terrain as a mesh and then make it have my water material, but that didn't quite work out, because it sticks out at random spots and it doesn't quite get me the results that I wanted.

    I am generating a terrain using some noise functions, and then apply it on a unity terrain.

    Does anybody have any ideas on what I could do instead?
     
  2. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    A noise function is unlikely to create a suitable river bed. If you just start pouring water on it will simply form pools. Keep adding more water and you will flood the while map.

    Conceptually rivers create their path by eroding the land as they flow. In practice this would be by lowering the land slightly where there is flow. This would encourage more water flow in that area, and eventually you get a river. Water falls are created by differences in the speed at which rock erodes.

    I'm not sure how to translate this into code. But most good procedural terrain systems do something like this. Noise is used as a seed, then cycles of erosion are applied to make the terrain more realistic.
     
    MakakWasTaken and SubZeroGaming like this.
  3. SubZeroGaming

    SubZeroGaming

    Joined:
    Mar 4, 2013
    Posts:
    1,008
    Beautiful response. Putting those Geology skills to work!
     
    Kiwasi likes this.
  4. Sciwiz12

    Sciwiz12

    Joined:
    Sep 25, 2014
    Posts:
    32
    Might I recommend this book by Daniel Schiffman: http://natureofcode.com/book/chapter-1-vectors/

    It uses Java and Processing instead of C# and Unity but the concepts are easily translated from one to the other, if I had to summarize it's a book about using code to model nature. Of course it's difficult to suggest a method for creating a procedurally generated waterfall without knowing how you have implemented your procedurally generated terrain.

    Bored Mormon does raise a good point about erosion, have you considered treating water as a special type of wind in terms of how the forces behave? I'm assuming you're implementing marching cubes for terrain?






    Wow, you know these rivers can get rather complicated. How about this, make a class for water and store it's physical values and properties, primarily and possibly exclusively it's weight by volume. We can then write a function to calculate the force of flowing water over time from the impact of gravity and friction on a particular volume of water and its corresponding weight. Then you can use perlin noise to get the density of each cube of terrain similar to the procedure performed in a marching cube algorithm except this time you're using the density of each cube to determine whether it is soft soil or not. Then you can use the force of gravity * the (volume of water * the density of water) to reduce the height values according to their density.

    As far as how to figure out the path of the river you need to calculate the width of the river which will increase gradually from the source until a certain point at which it will remain pretty constant until it reaches the delta. You need some sort of path calculating object to determine the path of least soil density between the starting point of the river and the ending point of the river so that you can use the result of the pathing algorithm to calculate the path.

    Anyway that's my two cents, hopefully that helps a bit.
     
    jjbish and Kiwasi like this.
  5. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    I'm doing something roughly like this: figure out a point high in the terrain where you want the river to start, then figure out a point lower in the terrain where you want the river to end. These two points could be selected in a variety of ways; maybe you want the river to start off-map or in a cave or something, and end in a lake. Then from the start point to the end point, you keep moving one heightmap unit at a time choosing the lowest point weighted by how close it is to pointing towards the end point with some randomness thrown in. If you can't find a lower point from your current point, pick the lowest available and push the terrain down there so it is now lower. This way you ensure the river is always going downhill and not uphill, and it will automatically "carve" through certain places if it gets stuck.

    This is not at all how rivers work in real life, but it's good enough in my opinion. ;)
     
    Kiwasi likes this.
  6. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    It probably good enough for most games, and easier to conceptualise and process then a full of geological model.
     
  7. MakakWasTaken

    MakakWasTaken

    Joined:
    Mar 26, 2015
    Posts:
    45
    I have decided to setup a github with my current progress, which is getting the easiest way down the mountain. I am having a hard time figuring out how to create the actual mesh.

    Something like this is what I am looking for, but I don't know how to apply this to a terrain.



    Link: https://github.com/Unknown-Studios/OneRiver
     
  8. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Are we talking unity terrains? If so just grab the height map value at the river position and push it down a little.
     
  9. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Now that I think on it, using a unity terrain to create water like erosion to make a river wouldn't be to difficult. I'm thinking something like this.
    • Create a terrain with noise
    • Create a particle system
    • Randomly scatter particles across your terrain
    • Move each particle in the direction of TerrainData.GetSteepness
    • Lower the terrain slightly along the path of the particles movement, based on the magnitude of steepness
    • Repeat until convincing rivers are formed
    You might also have to look at dealing with water pooling in hollows. If you are prepared to let the simulation run for ages you could use small spheres with rigidbodies instead of particles. That's probably something you want to set up to run overnight.

    Of course, all of this might well be overkill for a game. Most gamers won't have the geology to appreciate it.
     
    SubZeroGaming likes this.
  10. MakakWasTaken

    MakakWasTaken

    Joined:
    Mar 26, 2015
    Posts:
    45
    I am creating an online multiplayer game, and I think it would be absolutely awesome if the terrain changed based on time to make it more exciting.

    I can't seem to figure out how to rotate the particles, they always have the same angle. (I am using a quad mesh as the particle)
     
  11. MakakWasTaken

    MakakWasTaken

    Joined:
    Mar 26, 2015
    Posts:
    45
    I couldn't figure out how to rotate the particles, so I went with another solution: Creating a mesh that follows the waypoints.
    Which I got quite stuck on but now is getting an okay result except that half of the river isn't appearing:

    private void CreateMesh()
    {
    Mesh m = new Mesh();
    MeshFilter mf = GetComponent<MeshFilter>();

    vertices = new Vector3[path.movementPath.Count * 2];
    int[] triangles = new int[vertices.Length * 6];
    Vector2[] uv = new Vector2[vertices.Length];

    int curVert = 0;
    int curTri = 0;

    for (int i = 0; i < path.movementPath.Count; i++)
    {
    if (i != path.movementPath.Count - 1)
    {
    float angle = Mathf.Floor(Vector3.Angle(path.Vector3Path, path.Vector3Path[i + 1]) * 4f);
    Vector3 offset = new Vector3(2.5f * angle, 0f, 2.5f * (2f - angle));

    Debug.Log(offset);

    vertices[curVert++] = path.Vector3Path + offset;
    uv[curVert] = new Vector2(0, i);
    vertices[curVert++] = path.Vector3Path - offset;
    uv[curVert] = new Vector2(1, i);
    }
    else
    {
    vertices[curVert++] = path.Vector3Path;
    vertices[curVert++] = path.Vector3Path;
    }
    triangles[curTri++] = i; // 0
    triangles[curTri++] = i + 1; // 1
    triangles[curTri++] = i + 2; // 2

    triangles[curTri++] = i + 1; // 1
    triangles[curTri++] = i + 3; // 3
    triangles[curTri++] = i + 2; // 2
    }

    m.vertices = vertices;
    m.triangles = triangles;
    m.RecalculateNormals();
    m.RecalculateBounds();

    mf.sharedMesh = m;
    }


    But it always end up twisted and wrongly rotated.

    Does anybody have a idea on what I am missing?
     
  12. samf1111

    samf1111

    Joined:
    Sep 18, 2019
    Posts:
    16
    I know this thread died 7 years ago, but you can do this really easily by generating a voronoi texture and sinking parts of the land to make rivers. If you can't find a way to generate voronoi (like me) procedural, you can take a premade voronoi texture and rotate, scale, translate it by random values to create the illusion of unique rivers on every map.