News:

Simutrans Wiki Manual
The official on-line manual for Simutrans. Read and contribute.

An idea on how to create wider rivers

Started by Leartin, January 15, 2023, 10:53:45 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Leartin

Quote from: [C] Ranran on January 11, 2023, 08:17:44 PMIs it possible to create a wide river using such a system? It is strange because all the rivers in simutrans are narrow. A large river should be several kilometers wide. A long bridge is needed to cross a big river. In simutrans it always happens in oceans or lakes...

Step 1:
Current river generation gives us a number of connected tiles that are continuous and monotone - as in, they are (orthogonally) connected and depending on which end you start at, go never up or never down. Moreover, current river generation gives us levels - lower levels near the source are displayed as thinner rivers. Imagine these tiles as a list of coordinates and levels.
Now, for each list entry of level X*, If X is odd, add the coordinates of the tiles north and east as level X-1. If X is even, add the coordinates of the tiles north, east, west and south as level X-2. Don't add coordinates if they are higher than the current tile. Don't do anything at level 0. This would mean that wherever the river had level 0, it's one tile, where it had level1 it's two tiles and so on.
Then, try to place the river way on all these tiles autoconnecting to all surrounding rivers/waters. It doesn't matter if it isn't possible for some of the tiles due to slopes or other objects, as you are guaranteed from the original river that it's connected on at least one tile. It's only natural that a river is wider in flat, unoccupied land.
However, while this tells us where the river should be, it requires all river graphics to be almost full tiles, especially intersections.

*[This replaces the multitude of river thicknesses in tiles. To prevent that, use YX where Y is the number of different rivers, and add with level Y(X-1), Y(X-2) instead]

Step 2:
So the way graphics need to be aware or their surroundings and change accordingly. Too much just for rivers, but that goes essentially back to directional ways (or at least their graphics) - Similar to stations, instead of one straight river North-South, you'd need four: edge both sides (as we have currently), edge left, edge right, no edge. This is how many (especially japanese) addons operate already for their tracks, except currently you need to choose manually. Which is not feasible for these rivers, as you'd have players deconstruct parts of them and want the "inner" tiles to change when they become "outer" tiles.

Step 3:
Since you might rightfully say "that's way too many graphics for ways", perhaps allow tiles to be assembled from smaller tiles. That's something artists already do, but as part of the code it could be better on resources.
If we look at the example of a straight river tile again, both the left sides and the right sides are shared between two tiles. Same is true for the ways we already have - chances are the connecting side of a dead end is exactly the same as a regular way. There is even an example already implemented via back/frontimage: A station on both sides of the track simply reuses the graphics for a station on one side of the track.
So, if you split up all the graphics of a way in quarters, you end up with a lot of overlap you don't need. For implementation, I'd say allow up to four images with offsets to be tied to one "tile", and compose them back to front in that order. Whether they ought to be precomposed on load or when placed in game I don't know. The offset makes it possible to compose a 128-graphic from four 64 graphics, allowing tighter packing.



While I use numbered steps, each works on it's own, but gets better with following steps and more useful with previous steps. Can't really look at each individually without losing something.

Ranran

Quote from: Leartin on January 15, 2023, 10:53:45 AMStep 3:
Since you might rightfully say "that's way too many graphics for ways", perhaps allow tiles to be assembled from smaller tiles. That's something artists already do, but as part of the code it could be better on resources.
If we look at the example of a straight river tile again, both the left sides and the right sides are shared between two tiles. Same is true for the ways we already have - chances are the connecting side of a dead end is exactly the same as a regular way. There is even an example already implemented via back/frontimage: A station on both sides of the track simply reuses the graphics for a station on one side of the track.
So, if you split up all the graphics of a way in quarters, you end up with a lot of overlap you don't need. For implementation, I'd say allow up to four images with offsets to be tied to one "tile", and compose them back to front in that order. Whether they ought to be precomposed on load or when placed in game I don't know. The offset makes it possible to compose a 128-graphic from four 64 graphics, allowing tighter packing.
If this method is feasible, it could be applied to double-track (rail) or even more parallel tracks to provide a more realistic look.

Yona-TYT

@leartin always has good ideas, that's why (and also because of his great art) they admire him a lot around here. :D

isidoro

I always thought that a good river algorithm should try to reproduce what happens in nature.  First, it rains or snows.  Second, all that water goes downhill and is collected naturally in river basins.

So, my algorithm would be much rather simpler.

  0) Declare an array or integers the same size as the map to represent the amount of water in each tile.  Mark with -1 each sea tile.
  1) For all land tiles t, generate a stream.
  2) Set a threshold of water.  Tiles above that threshold will be river, lakes, etc.  Tiles below will be dry land.

This way a stream starting at tile t could be generated:
  1) Add +1 to the present tile
  2) Choose the following tile among the neighboring tiles, with the following conditions:
         2.0) It mustn't be a sea tile
         2.1) It mustn't have higher height than the present tile
         2.2) It mustn't have been visited by this stream before
         2.3) No other neighbor tile can have lower height than the chosen one
         2.4) If there's a draw, choose the one that divert less from the direction of (last chosen tile -> this tile) or, if a draw is met again, just random.  For example, if last tile was (10,10) and present tile is (10,11) and both (10,12) and (9,11) are equal candidates, choose (10,12)
  3) Repeat until there's no candidate to go on.

If that's too CPU intensive and that's not desired (but that will only be done at map design), do that only for a subset of initial tiles.

There's also a possibility to ignore initial tiles based on climates of even give a value greater than 1 to some tiles so that those tiles will increase the amount of water they give by that quantity...

prissi

Since the rivers in simutrans always end in the sea (if possible) and avoid going uphill, the current algorithm more or less does the same. The old difference is the starting tile, which is currently random.

Testing 1 million tiles (on a 1200 * 1200 map) with the pathfinder (i.e. above described algorithm) is totally out of the question.

The challenge is "only" to get the right starting tile.

A flooding algorithm making wider rivers may work also with the perlin map generator but likely fails with bitmap maps, since there would typically too wide flat areas.

_Hajo_

I've once done a rain and erosion algorithm to generate landscapes (based on perlin noise calculated heights like Simutrans uses). It already uses the concept of a flow to move debris downhill and it will collect in valley, deposit on shallow areas or be moved to the sea.

I can only concur with Prissi. while it works and produces quite nice landscapes, it is horribly expensive on the CPU.

Edit: See the screenshot. That's been some billion raindrops and it still is not as detailed as real mountains. But I think yiuz can see the erosion effects.

Ranran

Quote from: prissi on January 20, 2023, 05:50:57 AMSince the rivers in simutrans always end in the sea (if possible) and avoid going uphill, the current algorithm more or less does the same. The old difference is the starting tile, which is currently random.
I think what should be discussed in this thread is the algorithm for determining river width. Is there something like that in simutrans now? Humidity is not built into extended so I'm not familiar with it.
If the width of the river is determined by its length or elevation, it will be very monotonous, boring and unrealistic.
It may be wide because the flow increases when two rivers meet. The river that connects the lake and the sea may be wide.

isidoro

@prissi:  most of the calculations are repeated, so they can be cached.  And it has only to be done at map design.

The latitude and longitude of the "starting tiles" or the "fountains" of the rivers if wanted, could be given manually in a separate file, along with the name of the river, so that they could be reused for maps based on real heightmaps.


@_Hajo_: very nice image!  But we have two different problems (albeit perhaps with the same solution) here.  Eroding a perlin noise map vs. trying to figure out where the rivers go in reality if you get height map and build a ST map from it.


Quote from: [C] Ranran on January 21, 2023, 11:12:05 AMI think what should be discussed in this thread is the algorithm for determining river width.
[...]

Of course, and that's what we are talking about.  The algorithm I was suggesting would give not only where the river is but also how much water it has in every point, which can give a hint of the width.  But would it produce realistic rivers?

And when we talk about width, I think we are talking about rivers more than one ST tile width (they would be in fact lakes).