Mission on Mars: UV-Map generieren

Lesezeit: 7 Minuten

Mein Terrain ist ordentlich skaliert – nun generiere ich eine dem Mars entsprechende UV-Map: zur Analyse der Oberfläche soll wieder die Normal-Map herhalten.

Dieser Artikel entstand während meines 14-tägigen Angelurlaubs. Er zeigt die Vorgehensweise, um Texturen und Details auf Strukturen zu erzeugen. Die Vielzahl der eingesetzten Algorithmen, Hilfsfunktionen und Techniken erkläre ich dann in separaten Blogs – vorerst möchte ich aber so langsam etwas sehen, das sich lohnt „Marsoberfläche“ genannt zu werden.

Dieser Blog hier ist als erstes Script zu verstehen. um sich an das Thema heranzutasten. Die einzelnen verwendeten Algorithmen werden nachfolgend verbessert bzw. korrigiert.

Grundfarbe

Zunächst soll eine „Grundierung“ der UV-Map geschehen.

Wichtig ist hier und später bei der weiteren Dekoration, die allgemein gültige Skalierung. Das muss ich immer im Auge behalten:

Die UV-Map wird in 2048×2048 angeboten und entspricht damit etwa 50x50km auf dem Mars.
Ein Pixel entspricht damit etwa 24m.

Grundsätzliche Farbgebungen findet man z. B. bei Google-Bildersuche und dann hier: https://space-facts.com/mars/

Ich designe meine Maps immer im Tageslicht – folglich drehe ich auch erstmal in der APP die Lichter ein wenig höher:

Weiter wähle ich als vorherrschende Farbe den RGB-Wert: 241/127/91 – 0.94509/0.49803/0.35686 – f17f5b – ein „frischer“ rötlicher Sandton.

Die UV-Map erstelle ich als PHP-Image truecolor mit alpha und lade diesmal nicht die Datei „tex_be_tile1.png“ aus den vorherigen Beispielen:

Diese Funktion ergänze ich in meiner Tile-Generation aus Mission on Mars: Skalierung – Teil 2

Wo ist der Staub?

Staub bzw. Sand soll nun hinzugefügt werden. Die erste Frage ist allerdings, wohin genau? Dazu schaue ich mir die Normalenmap noch mal an:

Staub und Sand setzen sich ja nur auf den „relativ“ geraden Ebenen ab – mal von Windverwehungen abgesehen. Es gilt also diese Stellen ausfindig zu machen.

Eine DeltaE-Implementierung finde ich hier: https://github.com/renasboy/php-color-difference. Näheres dazu auch unter Wiki: https://de.wikipedia.org/wiki/Delta_E

Und ein abschließender Blur liefert mir das:

An den weißen (hellen) Stellen ist relativ glattes Terrain, so dass dort wahrscheinlich viel Sand liegt. Umgekehrt kann man bei den schwarzen (dunklen) Stellen von einem steinigen Untergrund ausgehen, da dort viele Steigungen und Unregelmäßigkeiten sind.

Sand generieren

Sand besteht aus kleinen Hügelchen und Verwehungen und Dünen. Erscheint also relativ fließenden, ohne große Störungen. Vielleicht sind ein paar kleine Unebenheiten drin, z. B. von überdeckten Steinen. Vielleicht scheinen diese Steine auch durch – sind also nicht vollständig von Sand überdeckt. Auch ist der Sand nicht unbedingt von einer Farbe, sondern zersetzt sich in mehrere Bestandteile.

Diese Überlegungen versuche ich umzusetzen.

Zuerst bastel ich mal die gesamte Textur zusammen, um in folgenden Blogs auf die einzelnen Algorithmen näher einzugehen.

Unebener Untergrund

Zuerst benötige ich eine fraktale Struktur. Dazu benutze ich den DiamondSquare-Algorithmus: http://www.lighthouse3d.com/opengl/terrain/index.php?mpd2

Wissenswertes dazu auch unter Wiki: https://de.wikipedia.org/wiki/Diamond-square_Algorithmus

Im Grunde geht es also darum, Wolkenbilder zu erstellen. Meine Umsetzung in PHP liefert z. B. dieses Bild:

 

Anschließend möchte ich terrassenförmige Gebilde daraus entstehen lassen – dazu hilft mir ein Algorithmus, der sich Voronoi-Diagramm nennt: https://de.wikipedia.org/wiki/Voronoi-Diagramm

Meine „Wolke“ sieht anschließend so aus:

Diese Map blurre ich und verschiebe sie ins hellere:

Anschließend erstelle ich eine Noisemap – nicht mit schwarz/weiß, sondern mit den beiden Grauwerten 0 und 15 (genau hingucken!):

Diese Noisemap addiere ich und erhalte meine endgültige Highmap für den Sand:

Nun geht es ans colorieren – und da ist weniger mehr (nicht zu krasse unterschiedliche Farben benutzen) – ich generiere eine „sanfte“ Wolke:

Die Grundfarbe meines Sandes ist ja f17f5b – also wähle ich zwei Farben – eine etwas dunkler als die Grundfarbe – die andere heller.

Meine Wahl fällt auf df6e4c  und  fe8965 – damit coloriere ich die Wolken-Map – schwarz wird zu df6e4c  – weiß zu fe8965, alle anderen Werte halt dazwischen. RGBs: (223/110/76), (254/137/101)

Das ist meine endgültige Farbmap für den Sand.

Steine generieren

Den Sand möchte ich mit einigen Felsbrocken aufpimpten. Dazu zeichne ich ein Polygon und lasse die Punkte ein wenig zufällig differieren. So baue ich mir ein paar Masken für Felsformationen zusammen. Die Steine werden später ziemlich klein auf der Map – ich generiere also kleiner Bilder – 256*256:

Wie schon beim Sand erzeuge ich eine Wolke, anschließend ein Voronoi-Diagramm, bei dem allerdings mehr Pixel in der Bildmitte sind:

Um gröbere Strukturen zu ergänzen, erzeuge ich eine Noisemap in 64*64 und skaliere diese auf 256*256 hoch:

Damit dekoriere ich wieder und abschließend benutze ich die Polygon-Maske:

Fertig ist die Höhenmap eines Felsens.

Als Felsfarbe nehme ich wieder zwei Farben in einer Wolke: 642b19 (100/43/25) und 703423 (112/52/35):

Nach Anwendung der Maske von oben erhalte ich meine endgültige Textur:

20 Steine generieren

Mittels obiger Vorgehensweise erstelle ich mir 20 unterschiedliche Steine – also 20 Highmaps h_rock_xx.png mit den passenden Texturen uv_rock_xx.png.

Im Einzelnen anzusehen unter http://www.mission-on-mars.com/blog/download/h_rock_xx.png (bzw.: uv_rock_xx.png) – xx von 00 bis 19.

Steine verteilen

Grundsätzlich könnte ich die Steine ja zufällig auf dem Sand verteilen, meist sieht das jedoch nicht naturgemäß aus. Wo ein Felsblock bzw. Stein rumliegt, liegt meistens auch ein zweiter. Dazu habe ich mir einen Algorithmus „Radial Noise“ ausgedacht, den ich in einem späteren Blog erkläre. Der Algorithmus generiert mir so eine Radial-Noise-Map:

Diese Map nutze ich zur Verteilung der Steine – und zwar in 4 Kategorien. Blaue sind winzige, grüne kleine, rote mittlere und weiße Punkte große Steine (letztere kann man hier sehr schlecht erkennen, da die Map transparent ist).

Winzige Steine sollen 5 Pixel, kleine 8, mittlere 20 und große 30 Pixel groß sein (damit sind die großen Steine 720m lang bzw. breit – das sollte reichen!). Gleichzeitig drehe ich die Steine zufällig um 1 – 350 Grad bei dieser Verteilung, so habe ich noch mehr Variationen. Ich erhalte zwei Maps: die Höhenmap für die Steinstruktur und die passende Textur dazu.

Herauskommt als UV:

Und als Highmap:

Ich verschiebe nun die Highmap des Sandes „nach unten“ und addiere die Highmap der Steine:

Anschließend kombiniere ich noch die Texturen von Sand und Stein:

Auf beide Maps wende ich die eingangs erstellte Maske an, die definiert, wo Sand ist – dabei benutze ich den Weißwert als „Pseudo-„Alpha:

Daraus generiere ich eine Normalenmap für Steine und Sand:

Und abschließend kombiniere ich diese mit meiner ursprünglichen Normalenmap:

In der APP sehe ich dann endlich, wie die neuen Texturen in Aktion aussehen:

Grundsätzlich gefällt mir das – aber da sind noch ein paar Fehler drin. Ebenfalls sind die Steine noch recht langweilig. Aber ich bin auf dem richtigen Weg.

Welche Fehler habe ich festgestellt?

Einige Algorithmen und Verfahren verwenden die Alpha-Maske falsch.

Generische Texturierung muss standardisiert werden.

Optimierung von Laufzeit und Zwischenergebnissen muss geschehen. Eine Strukturierung ist ebenfalls von Nöten.

Im Hinterkopf behalten: Nahtlose Texturen entwickeln; Stichwort „seamless“.

Variationen der Steine ist nicht gegeben: alle Steine sehen irgendwie gleich aus.

Weiterführende Links

Ich mache eine neue Kategorie „Grafik-Algorithmen“ auf und untersuche dort die einzelnen Parameter der Funktionen. Dabei achte ich auf eine einheitliche Struktur zur Generierung.

Der Wolken-Algorithmus ist hier erklärt: Algorithmus: Diamond-square

Voronoi-Diagramm: Algorithmus: Voronoi-Diagramm

 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.