Dev Blog
Hi, this is the Stranded III development blog (see also Forum Thread, Comment Thread).
Entry 33 - Rivers - March 7, 2016
130 days since the last update and no dev blog entry in 2016 yet? Let's change that!
Rivers
I fine tuned the terrain generation a bit and I'm currently working on random river generation.
My first primitive algorithm to create random rivers worked like this: Rivers start at random points. To calculate their flow direction I simply check all 8 adjacent heightmap heights and choose the one with the lowest altitude as successor. A river ends if there is no adjacent field with a lower/equal altitude than the current one. That's because water can't flow uphill.
For the following picture - which is basically a heightmap visualization - I set the altitude of rivers to 0 to make them very visible (black lines). Scale: 1 pixel = 1 m² (and yes, the black bottom left field is a bug. I just didn't bother fixing it yet)
click to enlarge
Here's a 3D world shot of a riverbed generated by this algorithm. For this shot I just reduced the terrain heights for the riverbed by 1 m. This doesn't work well because I only reduced one single heightmap point per river square meter. This works for straight rivers but leads to very bad results when you have diagonal rivers:
click to enlarge
So after this first quick approach I faced several problems:
1. Rivers look artificial because they are not curvy enough
2. Rivers stop in most cases and never reach the sea because chances that they just hit a hill are very high.
3. Changing only one single heightmap altitude per river "tile" is not sufficient to form a good looking riverbed. Also it doesn't allow different river sizes.
Strategy to solve problem #1: Rivers need a real direction. The algorithm to search the next river tile needs to be refined and it needs to take the current river direction into account instead of only checking the altitudes. Having a direction also means that I have more influence on the river course. The direction can be altered slightly with each step with a simple sine operation (of course cosine would work too! duh!). This should result in a more curvy riverbed.
I already started to implement this and it looks way more natural. Of course it needs some tweaking but the principle works very well:
click to enlarge
The altitude checks are disabled completely for the above shot and I limited the river length. I'm also doing 2 pixel steps which explains the gaps. My plan is to combine the altitude checks and the direction. The more a direction is off the calculated direction, the more altitude penalty will be added. This way the river will tend to choose the calculated direction but good altitudes in other directions can influence it.
Is this the only stuff you did since the last dev blog entry?
No, I did a lot of refactoring. I should stop that. Seriously. It's like premature optimization. It's death. It's stagnation. Don't do it in hobby projects unless your code is REALLY bad (and I mean goto-spaghetti-bad not just stupid-function-names-bad).
I also did some other things. For example: A class which allows me to render tiny numbers into textures (for debugging purposes) or converting a Java polygon filling algorithm to C#. By the way: The polygon filling is still by far the slowest step of my random map generation. It takes ~0.28 seconds for the sample map which has a size of 512² pixels. It took ~0.33 seconds before I made the polygon filler static instead of instantiating a new one for each polygon. I even considered to use the GPU to render the filled polygons but that would be somewhat dirty and it wouldn't work on headless servers later.
Concerns regarding development speed
I'm not fast enough. I won't finish this game within the next 10 years unless I invest more time. I want to push myself to work more on the game. Therefore I'll try to make at least one dev blog entry - with actual content - each week. From now on. Let's see if I can manage to do that!
Rivers
I fine tuned the terrain generation a bit and I'm currently working on random river generation.
My first primitive algorithm to create random rivers worked like this: Rivers start at random points. To calculate their flow direction I simply check all 8 adjacent heightmap heights and choose the one with the lowest altitude as successor. A river ends if there is no adjacent field with a lower/equal altitude than the current one. That's because water can't flow uphill.
For the following picture - which is basically a heightmap visualization - I set the altitude of rivers to 0 to make them very visible (black lines). Scale: 1 pixel = 1 m² (and yes, the black bottom left field is a bug. I just didn't bother fixing it yet)
click to enlarge
Here's a 3D world shot of a riverbed generated by this algorithm. For this shot I just reduced the terrain heights for the riverbed by 1 m. This doesn't work well because I only reduced one single heightmap point per river square meter. This works for straight rivers but leads to very bad results when you have diagonal rivers:
click to enlarge
So after this first quick approach I faced several problems:
1. Rivers look artificial because they are not curvy enough
2. Rivers stop in most cases and never reach the sea because chances that they just hit a hill are very high.
3. Changing only one single heightmap altitude per river "tile" is not sufficient to form a good looking riverbed. Also it doesn't allow different river sizes.
Strategy to solve problem #1: Rivers need a real direction. The algorithm to search the next river tile needs to be refined and it needs to take the current river direction into account instead of only checking the altitudes. Having a direction also means that I have more influence on the river course. The direction can be altered slightly with each step with a simple sine operation (of course cosine would work too! duh!). This should result in a more curvy riverbed.
I already started to implement this and it looks way more natural. Of course it needs some tweaking but the principle works very well:
click to enlarge
The altitude checks are disabled completely for the above shot and I limited the river length. I'm also doing 2 pixel steps which explains the gaps. My plan is to combine the altitude checks and the direction. The more a direction is off the calculated direction, the more altitude penalty will be added. This way the river will tend to choose the calculated direction but good altitudes in other directions can influence it.
Is this the only stuff you did since the last dev blog entry?
No, I did a lot of refactoring. I should stop that. Seriously. It's like premature optimization. It's death. It's stagnation. Don't do it in hobby projects unless your code is REALLY bad (and I mean goto-spaghetti-bad not just stupid-function-names-bad).
I also did some other things. For example: A class which allows me to render tiny numbers into textures (for debugging purposes) or converting a Java polygon filling algorithm to C#. By the way: The polygon filling is still by far the slowest step of my random map generation. It takes ~0.28 seconds for the sample map which has a size of 512² pixels. It took ~0.33 seconds before I made the polygon filler static instead of instantiating a new one for each polygon. I even considered to use the GPU to render the filled polygons but that would be somewhat dirty and it wouldn't work on headless servers later.
Concerns regarding development speed
I'm not fast enough. I won't finish this game within the next 10 years unless I invest more time. I want to push myself to work more on the game. Therefore I'll try to make at least one dev blog entry - with actual content - each week. From now on. Let's see if I can manage to do that!