Jump to content

Terrain erosion


Recommended Posts

Actually, I found the "Release" option, so I can compile the game itself without problems now, but if I start update-workspaces.bat via commandline "update-workspaces.bat --atlas" (I'm unsure if this is sufficient, at least there are 4 more files than without the --atlas option) and try to compile then, I get 2 errors. I have installed the pre-built libraries from the link above and copied lib/ and include/ into the game's libraries/wxwidgets/, like it is described in the Readme.txt. This is the message i receive (sorry that it is in german):

1>------ Erstellen gestartet: Projekt: AtlasUI, Konfiguration: Release Win32 ------
1>Der Buildvorgang wurde am 26.07.2012 01:12:27 gestartet.
1>InitializeBuildStatus:
1> Aktualisieren des Timestamps von "obj\AtlasUI_Release\AtlasUI.unsuccessfulbuild".
1>ClCompile:
1> Alle Ausgaben sind aktuell.
1> Canvas.cpp
1>c:\0ad\source ools\atlas\atlasui\customcontrols\canvas\Canvas.h(21): error C2504: 'wxGLCanvas': Basisklasse undefiniert
1>c:\0ad\source ools\atlas\atlasui\customcontrols\canvas\Canvas.h(37): error C2146: Syntaxfehler: Fehlendes ';' vor Bezeichner 'm_GLContext'
1>c:\0ad\source ools\atlas\atlasui\customcontrols\canvas\Canvas.h(37): error C4430: Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt.
1>c:\0ad\source ools\atlas\atlasui\customcontrols\canvas\Canvas.h(37): error C4430: Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt.
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(30): error C2614: 'Canvas': Unzulässige Elementinitialisierung: 'm_GLContext' ist weder Basis noch Element
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(30): error C2614: 'Canvas': Unzulässige Elementinitialisierung: 'wxGLCanvas' ist weder Basis noch Element
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(35): error C2065: 'm_GLContext': nichtdeklarierter Bezeichner
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(35): error C2228: Links von ".SetCurrent" muss sich eine Klasse/Struktur/Union befinden.
1> Typ ist ''unknown-type''
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(43): error C2228: Links von ".GetWidth" muss sich eine Klasse/Struktur/Union befinden.
1> Typ ist ''unknown-type''
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(43): error C3861: "GetClientSize": Bezeichner wurde nicht gefunden.
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(43): error C2228: Links von ".GetHeight" muss sich eine Klasse/Struktur/Union befinden.
1> Typ ist ''unknown-type''
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(43): error C3861: "GetClientSize": Bezeichner wurde nicht gefunden.
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(50): error C3861: "SetSize": Bezeichner wurde nicht gefunden.
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(50): error C3861: "GetClientSize": Bezeichner wurde nicht gefunden.
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(72): error C3861: "CaptureMouse": Bezeichner wurde nicht gefunden.
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(80): error C3861: "ReleaseMouse": Bezeichner wurde nicht gefunden.
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(85): error C2660: 'SetFocus': Funktion akzeptiert keine 0 Argumente
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(98): error C2653: 'wxGLCanvas': Keine Klasse oder Namespace
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(99): error C2440: 'static_cast': 'void (__thiscall Canvas::* )(wxSizeEvent &)' kann nicht in 'wxSizeEventFunction' konvertiert werden
1> Die Typen, auf die verwiesen wird, sind nicht verknüpft; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat.
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(99): error C2466: Zuordnung eines Arrays der konstanten Größe 0 nicht möglich.
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(99): error C2440: 'Initialisierung': 'int' kann nicht in 'const wxEventTableEntry' konvertiert werden
1> Quelltyp konnte von keinem Konstruktor angenommen werden, oder die Überladungsauflösung des Konstruktors ist mehrdeutig
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(100): error C2440: 'static_cast': 'void (__thiscall Canvas::* )(wxMouseEvent &)' kann nicht in 'wxMouseEventFunction' konvertiert werden
1> Die Typen, auf die verwiesen wird, sind nicht verknüpft; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat.
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(101): error C2440: 'static_cast': 'void (__thiscall Canvas::* )(wxMouseEvent &)' kann nicht in 'wxMouseEventFunction' konvertiert werden
1> Die Typen, auf die verwiesen wird, sind nicht verknüpft; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat.
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(102): error C2440: 'static_cast': 'void (__thiscall Canvas::* )(wxMouseEvent &)' kann nicht in 'wxMouseEventFunction' konvertiert werden
1> Die Typen, auf die verwiesen wird, sind nicht verknüpft; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat.
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(103): error C2440: 'static_cast': 'void (__thiscall Canvas::* )(wxMouseEvent &)' kann nicht in 'wxMouseEventFunction' konvertiert werden
1> Die Typen, auf die verwiesen wird, sind nicht verknüpft; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat.
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(104): error C2440: 'static_cast': 'void (__thiscall Canvas::* )(wxMouseEvent &)' kann nicht in 'wxMouseEventFunction' konvertiert werden
1> Die Typen, auf die verwiesen wird, sind nicht verknüpft; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat.
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(105): error C2440: 'static_cast': 'void (__thiscall Canvas::* )(wxMouseEvent &)' kann nicht in 'wxMouseEventFunction' konvertiert werden
1> Die Typen, auf die verwiesen wird, sind nicht verknüpft; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat.
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(106): error C2440: 'static_cast': 'void (__thiscall Canvas::* )(wxMouseEvent &)' kann nicht in 'wxMouseEventFunction' konvertiert werden
1> Die Typen, auf die verwiesen wird, sind nicht verknüpft; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat.
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(107): error C2440: 'static_cast': 'void (__thiscall Canvas::* )(wxMouseEvent &)' kann nicht in 'wxMouseEventFunction' konvertiert werden
1> Die Typen, auf die verwiesen wird, sind nicht verknüpft; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat.
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(108): error C2440: 'static_cast': 'void (__thiscall Canvas::* )(wxMouseEvent &)' kann nicht in 'wxMouseEventFunction' konvertiert werden
1> Die Typen, auf die verwiesen wird, sind nicht verknüpft; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat.
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(109): error C2440: 'static_cast': 'void (__thiscall Canvas::* )(wxMouseEvent &)' kann nicht in 'wxMouseEventFunction' konvertiert werden
1> Die Typen, auf die verwiesen wird, sind nicht verknüpft; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat.
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(110): error C2440: 'static_cast': 'void (__thiscall Canvas::* )(wxMouseEvent &)' kann nicht in 'wxMouseEventFunction' konvertiert werden
1> Die Typen, auf die verwiesen wird, sind nicht verknüpft; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat.
1>..\..\..\source ools\atlas\AtlasUI\CustomControls\Canvas\Canvas.cpp(111): error C2440: 'static_cast': 'void (__thiscall Canvas::* )(wxMouseCaptureLostEvent &)' kann nicht in 'wxMouseCaptureLostEventFunction' konvertiert werden
1> Die Typen, auf die verwiesen wird, sind nicht verknüpft; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat.
1> ScenarioEditor.cpp
1>C:\0ad\source ools\atlas\AtlasUI\CustomControls/Canvas/Canvas.h(21): error C2504: 'wxGLCanvas': Basisklasse undefiniert
1>C:\0ad\source ools\atlas\AtlasUI\CustomControls/Canvas/Canvas.h(37): error C2146: Syntaxfehler: Fehlendes ';' vor Bezeichner 'm_GLContext'
1>C:\0ad\source ools\atlas\AtlasUI\CustomControls/Canvas/Canvas.h(37): error C4430: Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt.
1>C:\0ad\source ools\atlas\AtlasUI\CustomControls/Canvas/Canvas.h(37): error C4430: Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt.
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(65): error C2039: 'SwapBuffers': Ist kein Element von 'Canvas'
1> C:\0ad\source ools\atlas\AtlasUI\CustomControls/Canvas/Canvas.h(20): Siehe Deklaration von 'Canvas'
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(219): error C2660: 'SetFocus': Funktion akzeptiert keine 0 Argumente
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(289): error C2440: 'static_cast': 'void (__thiscall GameCanvas::* )(wxKeyEvent &)' kann nicht in 'wxCharEventFunction' konvertiert werden
1> Die Typen, auf die verwiesen wird, sind nicht verknüpft; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat.
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(289): error C2466: Zuordnung eines Arrays der konstanten Größe 0 nicht möglich.
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(289): error C2440: 'Initialisierung': 'int' kann nicht in 'const wxEventTableEntry' konvertiert werden
1> Quelltyp konnte von keinem Konstruktor angenommen werden, oder die Überladungsauflösung des Konstruktors ist mehrdeutig
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(290): error C2440: 'static_cast': 'void (__thiscall GameCanvas::* )(wxKeyEvent &)' kann nicht in 'wxCharEventFunction' konvertiert werden
1> Die Typen, auf die verwiesen wird, sind nicht verknüpft; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat.
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(291): error C2440: 'static_cast': 'void (__thiscall GameCanvas::* )(wxKeyEvent &)' kann nicht in 'wxCharEventFunction' konvertiert werden
1> Die Typen, auf die verwiesen wird, sind nicht verknüpft; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat.
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(292): error C2440: 'static_cast': 'void (__thiscall GameCanvas::* )(wxFocusEvent &)' kann nicht in 'wxFocusEventFunction' konvertiert werden
1> Die Typen, auf die verwiesen wird, sind nicht verknüpft; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat.
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(483): error C2065: 'WX_GL_RGBA': nichtdeklarierter Bezeichner
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(484): error C2065: 'WX_GL_DOUBLEBUFFER': nichtdeklarierter Bezeichner
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(485): error C2065: 'WX_GL_DEPTH_SIZE': nichtdeklarierter Bezeichner
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(486): error C2065: 'WX_GL_STENCIL_SIZE': nichtdeklarierter Bezeichner
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(487): error C2065: 'WX_GL_BUFFER_SIZE': nichtdeklarierter Bezeichner
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(488): error C2065: 'WX_GL_MIN_ALPHA': nichtdeklarierter Bezeichner
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(492): error C2664: 'SectionLayout::SetCanvas': Konvertierung des Parameters 1 von 'Canvas *' in 'wxWindow *' nicht möglich
1> Die Typen, auf die verwiesen wird, sind nicht verknüpft; die Konvertierung erfordert einen reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat.
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(516): error C2061: Syntaxfehler: Bezeichner 'wxGLCanvas'
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(516): error C2039: 'GetClientSize': Ist kein Element von 'Canvas'
1> C:\0ad\source ools\atlas\AtlasUI\CustomControls/Canvas/Canvas.h(20): Siehe Deklaration von 'Canvas'
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(516): error C2228: Links von ".GetWidth" muss sich eine Klasse/Struktur/Union befinden.
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(516): error C2039: 'GetClientSize': Ist kein Element von 'Canvas'
1> C:\0ad\source ools\atlas\AtlasUI\CustomControls/Canvas/Canvas.h(20): Siehe Deklaration von 'Canvas'
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(516): error C2228: Links von ".GetHeight" muss sich eine Klasse/Struktur/Union befinden.
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(516): error C2660: 'AtlasMessage::MessagePasser::Add': Funktion akzeptiert keine 3 Argumente
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(516): error C2143: Syntaxfehler: Es fehlt ';' vor ')'
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(516): error C2143: Syntaxfehler: Es fehlt ';' vor ')'
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(539): error C2143: Syntaxfehler: Es fehlt ')' vor '}'
1>..\..\..\source ools\atlas\AtlasUI\ScenarioEditor\ScenarioEditor.cpp(539): error C2143: Syntaxfehler: Es fehlt ';' vor ')'
1> Code wird generiert...
1>
1>Fehler beim Erstellen
1>
1>Verstrichene Zeit 00:00:01.04
2>------ Erstellen gestartet: Projekt: ActorEditor, Konfiguration: Release Win32 ------
2>Der Buildvorgang wurde am 26.07.2012 01:12:29 gestartet.
2>InitializeBuildStatus:
2> Aktualisieren des Timestamps von "obj\ActorEditor_Release\ActorEditor.unsuccessfulbuild".
2>ClCompile:
2> Alle Ausgaben sind aktuell.
2>ResourceCompile:
2> Alle Ausgaben sind aktuell.
2>LINK : fatal error LNK1181: Eingabedatei "..\..\..\binaries\system\AtlasUI.lib" kann nicht geöffnet werden.
2>
2>Fehler beim Erstellen
2>
2>Verstrichene Zeit 00:00:00.07
========== Erstellen: 0 erfolgreich, Fehler bei 2, 16 aktuell, 0 übersprungen ==========

I'm pretty unsure what to do now (not that this has been different at anytime :P ), I guess that there are still problems with the wxWidgets?

Link to comment
Share on other sites

  • 3 weeks later...

Just came across this in a page Myconid linked to: using a normal map that is larger than the terrain heightmap to 'fake' the appearance of higher resolution terrain.

Without normal map:

uxKIpl.jpg

With normal map:

FuI2ul.jpg

In other words, if anyone is considering making terrain erosion scripts, they may as well consider making them output both a heightmap and a (higher resolution) normal map.

Link to comment
Share on other sites

  • 3 weeks later...

Now that I got my 3D support back today I had to try something

Here's the result of a first approach to generate a more realistic/random looking reliefmap/heightmap/terrain shape. It's only generated by a total scratchy random heightmap with a (very simple) erosion function flattening it several times (and sanely rescaling it at the end). The type of erosion is more like cracked rocky earth after an earthquake is decaying from sun erosion and a bit of random wind/quakes that make the material fall down. So it looks more like sandy ground without much wind and without water that gathers in streams. I'm going to add other erosion types later. In addition, to make cliffs possible, I think about filling in some geological activity like plates shifting or lava bubbles hovering ground. But here's what this very early state with only a few lines of code throw out:

post-14196-0-36483300-1346973519_thumb.j

...and the random map: fexor_hightmap.zip

Of cause it is very hard to predict how such random terrains look like and it will take some effort to make it well playable but I think that will be possible.

EDIT:

More interesting structures can be got with directed erosion (similar to wind would do):

post-14196-0-45554300-1347020781_thumb.j

The screenshot shows the map generated by fexor_hightmap2012-9-7.zip with seed 5201.

EDIT:

An additional screenshot of a relief map generated with only subtracting directed erosion with terrain painted by height.:

post-14196-0-54858800-1347277981_thumb.j

... the scale does not fit the unit/building sizes, yet.

EDIT:

A simple "playable" map done with erosion can be found here: http://www.wildfiregames.com/forum/index.php?showtopic=16535

Edited by FeXoR
Link to comment
Share on other sites

  • 8 months later...

Help! I got stuck with erosion functionality somehow...

There are generally some different (abstract) erosion types:

- Decay erosion: Caused by sun, gravity and slight vibrations of the earth. Implementation: Easy and fast.

- Directed erosion: Caused by wind or sun mainly coming from one side. Implementation: Fast but not that easy to adjust by parameters.

- Water drain erosion: Caused by rain draining downhill forming rivers and gathering in pits. Implementation: Slow and not really working at all.

Maybe I didn't find a good approach at all for water drain driven erosion. I mainly implemented some general functions to handle calculations for scalarfields and vectorfields. I use a discrete version of vector analysis which may in the end be a bad way to do this. Maybe an algebraic approach would be better and faster.

Here's what I got:so far:

discreteVectorAnalysis.zip

Some basic functions for discrete vector analysis. The first part works for any dimension but is emmensly slow. So I added some 2D functions that are much faster later in the file.

fexor_hightmap.zip

A random map to test things (very unorganized, sorry). In it many ways to simulate and apply the different types of erosion and visualize the multiple fields. The only function that seams to work for water drain erosion is getWaterDrainMap(). Uncomment line 858 to paint it (for color code see drawFieldAbsOnTiles() line 165). However, I can't seam to find a way to scale it right to do something sane. BTW: It ignores the height of the water so in pits it's somehow singularly.

(For a little orientation: Functions ending with DVA are extremely slow so avoid them. Functions without DVA and 2D are (more or less) stand alone functions not needing discreteVectorAnalysis.js )

I tried to avoid "multi step" water drain simulations (like suggested by myconid) because they are so slow. Maybe it sinply can't be done without multiple simulation loops for each erosion step.

If anyone has any idea or information about how the transported ground material depends on the amount of water and it's speed draining through this field - that would greatly help! As well I'm not exactly sure how water speed depends on steepness (and/or how water distributes depending on it).

Screenshots:

Just a hightmap formed by decay erosion:

post-14196-0-40148200-1368276816_thumb.j

Water drain field on the same heightmap (water removed to see the bottom of pits):

post-14196-0-20850000-1368276862_thumb.j

Color code: Amount of water draining through the field: yellow (not much), neon green, green, light blue, blue, purple, red (very much)

Edited by FeXoR
Link to comment
Share on other sites

Hm. I got it working (as far as I can tell as I planned).

Some screenshots and the evolution of the map after a different number of water drain erosion steps:

[steps: 0 (just a random heightmap), 1, 2, 5, 10, 20, 50, 100, 100 (zoomed out)]

post-14196-0-02072300-1368304630_thumb.jpost-14196-0-34654700-1368304671_thumb.jpost-14196-0-12839900-1368304688_thumb.jpost-14196-0-24822200-1368304704_thumb.jpost-14196-0-33726200-1368304719_thumb.jpost-14196-0-59733500-1368304731_thumb.jpost-14196-0-70271500-1368304747_thumb.jpost-14196-0-41380900-1368304766_thumb.jpost-14196-0-33338400-1368304781_thumb.j

...so it somehow works. There are still no signs of "riverbeds" though x)

I tried to apply it to a more smooth heightmap (like the one in my last post) but still no riverbeds.

Maybe I have to take into account material of different hardiness?

At least it gives a quite different shape (more spiky hills and more flat low areas) than the other erosion functions (though it's quite slow ofc.).

I don't understand the effect of the "seepage". It only seams to strengthen (lower values) the effect so higher seepage but more loops give about the same result as before. (If I rescale the water drain speed field to a fixed value before applying it changing the seepage does seam to have no impact at all).

Maybe I'm doing something wrong again x)

However, I am not entirely sure that the library functions work properly or can be defined better/faster etc. so if someone would be willing to look through at least the 2D part at the end that would help me greatly.

fexor_hightmap.zip

Any help/suggestions/ideas very welcome!

Edited by FeXoR
Link to comment
Share on other sites

I think the fact that the water is flat doesn't help you with not seeing riverbed, which with such a function would be at different heights.

I suggest you try this erosion on a tilted plane with minor differences in height level and check how it looks like.

Link to comment
Share on other sites

I suggest you try this erosion on a tilted plane with minor differences in height level and check how it looks like.

Yes, I thought about that too.

Result (pretty equal with all functions including your proposal of applying getWaterDrainMap result as the initial water distribution for another run):

post-14196-0-66515900-1368350718_thumb.jpost-14196-0-88105200-1368350732_thumb.jpost-14196-0-40489400-1368350745_thumb.jpost-14196-0-40932900-1368350759_thumb.j

...so still no riverbeds.

What I actually do:


myReliefmap = getDifferenceOfFields2D(myReliefmap, getDiv2d(getProductOfFields2D(getRescaledField2D(getWaterDrainMap(myReliefmap, 0), 1), getGrad2d(myReliefmap, false))));

With:

- myReliefmap: The heightmap the erosion should be applied to (a scalar field).

- getGrad2d(myReliefmap, false): The slope vector field (the 2D projection of the normal vectors). I assume the water speed between tiles depend on the vectors length (which might be wrong since it might be the square of it or something). The second argument just means that the field is generated assuming myReliefmap is not "wrapped" (top +1 = bottom, right +1 = left).

- getWaterDrainMap(myReliefmap, 0): The amount of water draining through each tile (calculated downhill, a scalar field). I scale this to have a maximum value of 1 (with getRescaledField2D) and than scale the slope with that (with getProductOfFields2D() assuming the amount of material carried by water equals the waters impuls = amount * speed [assuming its density is 1]). The second argument is the "seepage" (how much water sinks into the ground and so is lost to run further downhill each tile it passes).

- getDiv2d: Calculated the amount of material carried from one tile to the other downhill. Second argument is "wrapped" like in getGrad2d().

- getDifferenceOfFields2D: Actually applying the change to the heightmap.

NOTE: The only real difference between this and "decay erosion" (where just some material "falls"/"rolls" downhill) is that the slope field is scaled with the amount of water gathering in "channels". This is (in opposite to everything else) a global effect and so takes much longer to calculate.

What we might miss is that we need to calculate the "pressure" of the water towards the ground. That would be proportional (maybe not, maybe square or something) to the "bending" of the ground (where the water is driven upwards - in holes with positive bending - it carries away more while leaving material where it's "falling" - on hills/ledges with negative bending). Not sure right now how to calculate it though it should be similar to how to get the slope by grad(heightmap). So the bending would be the differentiated slope field (this cannot be grad because the slope field is a vectorfield though).

So small "hills" are lengthened downhill (the direction the material is transported) while shortened uphill (since there will be a "hole"). Mainly the same thing with holes (dug out downhill while filled uphill). That's what may "dig" riverbeds. (For physicists: The second-order term might be needed to generate riverbeds). EDIT: Indeed the pressure is (at constant density) the square of the speed.

I can't find any formular for this (material carried away by water "raining" down equally distributed on a given heightmap). Instead I find tons of formula to calculate the waters pressure, speed, density (though it's nearly incompressible, tztz) dependent on each other or the width of riverbeds dependent on the amount of water etc..

Further thoughts:

Maybe it's:

div(grad(heightmap)) * grad(heightmap)²

div(grad(heightmap) / abst(grad(heightmap)) * grad(heightmap)²)

div(grad(heightmap) * grad(heightmap)²)

div(waterAmountField * grad(heightmap)) * grad(heightmap)²

div(waterAmountField * grad(heightmap) / abst(grad(heightmap)) * grad(heightmap)²)

div(waterAmountField * grad(heightmap) * grad(heightmap)²)

???

(I assume here that the water speed equals the slope = grad(heightmap). If anyone knows PLZ tell me!)

EDIT: V should be proportional to heightDifference**0.5 so V² proportional to dH proportional to p...

1/2 m*v² + p + m*g*h = const (constant energy) while E(pot) just drives the process (and should not have any impact on the carried material)

So p*E(kin) proportional to waterAmount * dh**2 might be the amount of material carried...

Makes: getWaterDrainMap(heightmap) * grad(heightmap)² (this has no direction though so * grad(heightmap) / abst(grad(heightmap)) or simply calculate it by directly comparing tiles...)

So still no real clue and any input welcome.

Edited by FeXoR
Link to comment
Share on other sites

I'm not sure you can create riverbeds unless you make rivers remove some amount of ground, and make them remove more stuffs the deeper the water is (linearly, likely) so rivers will tend to dig. Given you avoid multi-step, I can't think of much better.

Perhaps try to run a little rain/wind erosion first, to get a better map.

Link to comment
Share on other sites

This is the hack WORKING!!! :crazy:

...somehow...

Now we have to get rid of the resonance...

post-14196-0-84222400-1368365198_thumb.j

(Seed 710)

erosion2013-5-12.zip

(I made a mistake before: I assumed getWaterDrainMap() returns the amount of water that drains through a tile. But it return the amount of water that drains through a tile per time! So the waters speed is already in it!)

wraitii: The ramp was a good idea. I'd never have chosen values needed to get rivers if I had used a more natural heightmap because I had never seen there actually is something (because of the resonance).

The used functions are only:

getWaterErodedHeightmap() line 684

that uses getWaterDrainMap() line 603

...so that should be quite easy to debug... *hope*

NOTE: The many lines commented out in getWaterErodedHeightmap() are the version assuming getWaterDrainMap() returning the amount of water only, not the amount per time (which was wrong, see above).

EDIT: Additionally not all tiles are taken into consideration (the last raw and line) in getWaterErodedHeightmap(). I fixed that but it does have no effect on the resonance.

After the fix I'm quite sure getWaterErodedHeightmap() is correct so the problem has to be in getWaterDrainMap().

Edited by FeXoR
Link to comment
Share on other sites

FeXoR: I don't think you posted the files.

Oh, maybe I posted an old version, so again:

erosion2013-5-12b.zip

What do you mean by the "resonance"?

Tiles with even values for x+y are somehow independent of tiles with uneven values for x+y

I had something like this before and it turned out that the implementation indeed handled x and y comparisons totally independent on each other. In principle there is nothing wrong with that. But in some cases they are not only independent in a single call of the function but stay independent over multiple applies. That can cause "resonance" in space (not as normally in space and time).

First some strange screenshots (all of the same seed 710 of the version above):

First again the hightmap the manipulation started from:


for (var x = 0; x < mapSize + 1; x++)
for (var y = 0; y < mapSize + 1; y++)
myReliefmap[x][y] = x + randFloat(- mapSize / 10, mapSize / 10);

...so just a ramp increasing towards x direction with a noise of an amplitude of 1/10 of the total height difference:

post-14196-0-78972300-1368389102_thumb.j

Then we apply the changes of the functions mentioned in my previous post and get (with seed 710):

post-14196-0-62855600-1368389188_thumb.j

Added code as final heightmap manipulation:


for (var x = 0; x < myReliefmap.length; x++)
for (var y = 0; y < myReliefmap[x].length; y++)
if ((x+y)%2 == 0)
myReliefmap[x][y] = myReliefmap[(x+1)%myReliefmap.length][y];

This sets all fields with even values for x+y to the height of the "next" field with uneven value for x+y:

post-14196-0-41590100-1368388213_thumb.j


for (var x = 0; x < myReliefmap.length; x++)
for (var y = 0; y < myReliefmap[x].length; y++)
if ((x+y)%2 == 1)
myReliefmap[x][y] = myReliefmap[(x+1)%myReliefmap.length][y];

This sets all fields with uneven values for x+y to the height of the "next" field with even value for x+y:

post-14196-0-21523800-1368388377_thumb.j


for (var x = 0; x < myReliefmap.length; x++)
for (var y = 0; y < myReliefmap[x].length; y++)
myReliefmap[x][y] += myReliefmap[(x+1)%myReliefmap.length][y];

This now adds the height of the "next" field (so even if the actual field got an uneven value for x+y and the other way arround) to the actual fields height:

post-14196-0-46410400-1368388795_thumb.j

...so there is nothing but some noise at the places I thought to see rivers ...otherwise it's just a smoothed version of the original ramp.

And just for comparison:


for (var x = 0; x < myReliefmap.length; x++)
for (var y = 0; y < myReliefmap[x].length; y++)
if ((x+y)%2 == 1)
myReliefmap[x][y] += myReliefmap[(x+myReliefmap.length-1)%myReliefmap.length][y];

post-14196-0-38949500-1368390289_thumb.j

And than I didn't believe what I saw:


for (var x = 0; x < myReliefmap.length; x++)
for (var y = 0; y < myReliefmap[x].length; y++)
myReliefmap[x][y] += myReliefmap[x][((y+myReliefmap[x].length)-1)%myReliefmap[x].length];

...so this is mainly the same as before just adding the height of the field with 1 lover y value instead of this with a x value 1 higher, but:

post-14196-0-46791100-1368389669_thumb.j

I might miss something here because it looks exactly like:

myReliefmap[x][y] = x * y;

But I don't get what's happening here!

No signs of flaws left, btw.

Well, at least I got some nice shapes x)

Trying to link them by adding diagonal calculations...

(Who can explain the last picture is my hero for the day!)

(Who can fix the functions is the hero for the week! ;))

Edited by FeXoR
Link to comment
Share on other sites

Some interesting stuff: your line 674 is actually required and does all the work.

I tried *0.5 the waterDrain variable: now it did nothing. Setting it to 2 gave odd results. 5 gave the same.

Looking at your code, it doesn't seem too sane: first you only move the ground for x+1 and y+1, might want to do it at least for w-1 and y-1 too, if possible all 8 corners.

Secondly, the way you calculate the water drain map seems alright, but it has a side effect: it seems to me like in the current implementation this means all water will flow down to the lowest point on the map (locally), with no respect for possible pond formations… You need to take into account the water height when calculating height difference, I think it would alleviate the effect. Furthermore, you should make each square retain a little water (percentage) so you will get some rivers as you can keep track of where water runned before going down. If you then use my method of recreating the water drain using the first water drain distribution, you should get really good results.

Otherwise seems fine.

edit: or keep adding water each frame uniformly as if it was actually raining, losing a little every turn too to simulate absorption.

Link to comment
Share on other sites

Some interesting stuff: your line 674 is actually required and does all the work.

Yep, I noticed. Though I'm still not sure why.

I tried *0.5 the waterDrain variable: now it did nothing. Setting it to 2 gave odd results. 5 gave the same.

It does something e.g. smoothen everything (though not much different from erosion simulating material just falling downhill). What it does not do is "unlinking" tiles with even and uneven values of x+y - and as sad as it is I have to admit this seam to be the cause of the river like structures. I still hope though because it somehow looks to good to be just numerical artifacts.

Looking at your code, it doesn't seem too sane: first you only move the ground for x+1 and y+1, might want to do it at least for w-1 and y-1 too, if possible all 8 corners.

Yes, I've done this right away (to get rid of the even/uneven noise). The result is just smoothing out the random noise of the initial ramp (mainly). There might still be some small "rivers" but no material seam at all to be carried further then one tile which is odd after 200 cycles. The effect is so sensitive that the diagonal calculations of the water drain and the carried material has to be scaled with 1/(2)**0.5 to take into account the higher distance of the center of that tiles - otherwise diagonal crinkles appear.

And just to make that clear: I'm quite sure it is sane. For each tile I calculate the material carried over the border to it's positive x and y direction - not from the field away or towards it but above that border. So the calculation is not really done for the current field but for two borders of the grid. Calculating those for all tiles however exactly calculates each border once. Each tile might have it's material changed up to 3 times: 2 times when the calculation reaches the field (get or loose material over its top or right border), when the calculation reaches the field with the x coordinate 1 lower and the same y coordinate then the field in question (material transport over it's left border) and the field with the same x coordinate and a 1 lower y coordinate (over the fields bottom border).

So adding the x-1 and y-1 field to compare does nothing but double the effect (because all borders are calculated twice). From the quality point of view it's exactly the same.

I hoped the diagonal fields to fix the issue but that only eliminates the visual "rivers" entirely.

Secondly, the way you calculate the water drain map seems alright, but it has a side effect: it seems to me like in the current implementation this means all water will flow down to the lowest point on the map (locally), with no respect for possible pond formations… You need to take into account the water height when calculating height difference,

Yes, that's true. And I don't see another sane way to get rid if the "singularities" in local minima. However, that means I have to calculate it several loops (I think). I agree that ignoring water hight might be one real flaw though.

I think it would alleviate the effect. Furthermore, you should make each square retain a little water (percentage) so you will get some rivers as you can keep track of where water runned before going down. If you then use my method of recreating the water drain using the first water drain distribution, you should get really good results.

Otherwise seems fine.

edit: or keep adding water each frame uniformly as if it was actually raining, losing a little every turn too to simulate absorption.

Sounds like a good idea.

Just to explain why I chose the "static" version with the water not added to the fields height: This calculation is somehow the lim(t -> inf; integral(0 to t; WaterVolume/time)) for a static heightmap on each tile (which seamed nice). But indeed this describes only the unnatural case that no water is "lost".

THX much for your reply. I thought I was totally stupid not to find the cause. But you hit mainly the same points as I did so I seam to do at least some things sane.

Rewriting the water drain and adding a field that contains all information "unshifted" (so for example each field contains 4 slope values - for each border of the field - rather than just 2 for the borders towards positive coordinate directions just to make sure therein lies no problem).

EDIT: Though somehow "cheated" (and still a bit noisy) we definetly got some rivers going here:

post-14196-0-01614200-1368485177_thumb.j

Some seeds might be not so good so try 5 or so out: The screenshot is from seed 7752.

erosion2013-5-14.zip

The "hack" is from line 1073 to 1094. It splits the map in two maps, one only containing tiles with even, the other with uneven values for x+y, then applies a non-linear function to the height values (x³) and finally fuses them back additive to one map. That strengthens the structure otherwise barely to see and this is something looking quite like riverbeds. Note that this only seams to work for a "strength" parameter of exactly 1/4.

@wraitii: The "multi way" calculation of material movement is in there but documented out. Not much more done yet.

Edited by FeXoR
Link to comment
Share on other sites

That's looking pretty good :) .

I'll be on holidays for the rest of the week so I'll give a look at your code this week-end/on monday (public holiday in France).

I'll try to get stuff done until then (including cleaning up the many fail tries and debug code). I'll try to explain a bit how to play around with the parameters to test the functionality/outcome in different situations so flaws can emerge and what kinds of parameters are useful/have an effect (in the long run it would be nice if erosion functionality could be used as a global filter and a local painter for atlas and ofc. for random maps).

What if we used these kinds of "realistic" maps for a "battle" game mode? Something like Total War multiplayer where players choose their units and upgrades and fight on a battle map (no construction or bases).

That would work.

But (without any disrespect to your idea - indeed I like different game modes) my focus would be to make the entire game (including structures) work on realistic terrain (while the terrain has to be scaled to the structures ofc.), not to make a game mode working on realistic terrain. For me this is part of "historical accuracy" because indeed civilizations had to deal with advantages/disadvantages in resources/space to build etc. given by terrain, ground type, flora and fauna inside there territory.

Still there should be very balanced maps to ensure a non-frustrating (luck independent) multi-player experience: http://www.wildfireg...160#entry268242

And now I'll jump upon the code getting it by it's throat ;)

Edited by FeXoR
Link to comment
Share on other sites

Here's a version with a much cleaner and easier to read function. It also does not need any additional function so in principle could be copied and pasted anywhere and be used (for the map the rmgen library is still needed though). It still only produces riverbeds if the strength is set so high that interference appear. However, to clean up the interference only one decay erosion (so only a range of one tile) is needed (and not the evil hack like in the last version. Definitely a progress:

erosion2013-5-14b.zip

To play with:

The function in question: getWaterErodedHeightmapStandalone line 783

Parameters to play with:

- Number of erosion processes: Line 969 (currently 200)

- The attributes the function takes: Line 1015 (description of the attributes in the line before)

- Smooth the noise: Document in line 1021 (Applies a simple decay erosion once. Rivers will be harder to see but are still there)

- Where the magic happens: Line 869 (Here the question is: What's the correct function? E.g. just multiplying the current version with 1/2 destroys all "river digging")

Not much "qualitatively" changed though.

EDIT: Some more thoughts:

Information we have:

- Slope := Dh = (dh/dx, dh/dy)

with h = height of ground, D = Del operator, d/dx, d/dy the partial derivation in space (local) in the given direction.

(This all is meant for the borders between tiles)

- Volumetric flow rate: Q = W*H*v = dV/dt

(We assume dV/dt depends linear on Dh and V is distributed dependent on the arithmetic mean. That might be wrong)

(We could use the harmonic mean or the root mean square easily while the geometric mean might be harder to use)

with W = tile width, H = water depth, v = water velocity in the x/y plane, V = water volume, d/dt the partial derivation in time

(This all is meant for the borders between tiles. Assume W = 1)

Information we might additionally need:

- Decouple water velocity and depth (should be easily and should be the next step)

-> Would additionally grand: water gravimetric potential energy, water kinetic energy, gravimetric force (and maybe water pressure)

(That would mean we had all parts of the incompressible Navier–Stokes equation - if that helps in any way (which is questionable) because we have to assume the water velocity reaches it's critical speed on every single tile to be constant in time)

- Water pressure (may additionally need the grounds bending)

- Stress at (near) the ground and the critical stress needed to pick up material. I'd prefer to do without it because that would mean more constants to assume/tweak.

What's to be done next (imo):

- Decouple water velocity and depth

@wraitii: As you suggested we could then use the water depth as water derivation map for the next run

- Implement harmonic, root square, and geometric water distribution (I think this might really matter)

Any ideas welcome.

Edited by FeXoR
Link to comment
Share on other sites

I think you get artifacts because you consider points and not surfaces, which is what you actually ought to consider. Diagonal points can make a lot of difference in the water flow, and this is probably where your results are wrong.

Your current implementation simulates constant raining, which should give a good enough result but would be better if you kept the water map over every frame, I think (twist it though, because given your algorithm it would be much too strong. You'd need to lower the strength). In that case, you need to lose some water (multiply WaterFlow by an arbitrary constant).

For the rest, seems good.

Link to comment
Share on other sites

I see that this has so much potential and would make the game a Different RTS, from all the others produced in, like, history. Kind of a new level. Realistic terrain could really push up the quality, be what makes 0AD stand out and amaze newcomers, when they see screenshots.

I think that if this kind of terrain script, after it has been worked on, must implicate that maps have to be much larger.

One can think subconsciously that, given the map size and terrain erosion idea, buildings would be like 1km2 large, and screw up this feature in some parts of the map, basically, the ones where the cities are, because when you put a building the ground goes flat.

http://www.wildfiregames.com/forum/index.php?showtopic=16169&st=20

This is a map with kinda terrain erosion feature, worked with Atlas, which I could continue to make.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...