Mission on Mars: Shader mit Normalmaps

Lesezeit: 5 Minuten

Um zwischen dem Mesh-Grid noch Details vorzutäuschen, benutze ich eine Normalmap. Diese generiere ich gleich am Server und passe meinen Shader entsprechend an.

Mesh verbessern

Die deutlich sichtbaren Diagonalen im Mesh-Aufbau verdanke ich der Splittung meines Quadrates in zwei Dreiecke:

Eine homogenere Splittung wäre in vier Dreiecke zu teilen:

Normalmap

Ich berechne ja für jedes Dreieck seine Normale mittels der drei Eckpunkte. Innerhalb des Dreiecks habe ich allerdings keine Kontrolle über die Normalen, wenn ich nicht eine sogenannte Normalenmap einsetzen würde. Ähnlich der Textur gibt diese Map die Normalen an den gewünschten Zwischenräumen an. Als Bilddatei sieht eine Normalenmap so aus:

Die RGB-Werte der Bildes geben dabei die Normalen-Vektoren an: rgb = (x,y,z). Näheres dazu hier: https://de.wikipedia.org/wiki/Normal_Mapping

Ich kann die Normalmap aus drei nebeneinander liegenden Punkten meiner Highmap berechnen, hab ich doch schon die Funktion aus drei Punkten die Normale Gfxlib::normalCCW.

Auch die neue Funktion highmap2normalmap ist es Wert in die Grafikbibliothek aufgenommen zu werden:

Hier habe ich noch einen Stärkefaktor (default=1.2) eingebaut, dann berechne ich über drei nebeneinander liegende Punkte die Normale. Hier mit y=-y, um der Fläche gerecht zu werden. Die Highmap habe ich um je einen Pixel in x und y vergrößert – sonst krieg ich an den Rändern keine Normalen zusammen:

Mehrere Texturen gleichzeitig laden

Der Server liefert mir nun:

Es sind also zwei Dateien, die für das Tile heruntergeladen werden müssen. Im gfxTile3d reagiere ich so auf die asynchronen Downloads:

Initial setze ich den Counter auf 2 und lade gleichzeitig beide Dateien nachdem ich die Informationen per JSON erhalten habe:

In den Requests reagiere ich nun auf den Gebrauch der Textur:

Ist alles geladen, springt meine Update-Funktion an:

Cocos2d-x Material erweitern

Wie schon unter Cocos2d-x: Source-Code modifizieren erklärt, erweitere ich das interne Material um eine weitere Komponente – der Normalmap – in CCMaterial::parseSampler

Weiterhin ergänze ich die folgende Funktion – analog der Textur:

Materialdefinition anpassen

Nun kann ich auch die Normalmap parametrieren und zwar in tile3d.material:

Fragment shader mit normalmap

In der vorherigen Version habe ich nur die Normalen der Punkte berücksichtigt:

Nun hole ich mir zusätzlich die Normalen aus der übergebenen Datei:

Hier ist zu beachten, dass ich die selben Koordinaten der UV-Textur für die Normalmap benutze. Dass heißt, dass mit diesem Shader zwingend UV und Normalmap die selbe Größe haben müssen!

Diese beiden Normalen blende ich nun ineinander:

Die blendNormals-Funktion halte ich vorerst einfach:

Wissenschaftlich Abhandlungen, wie man am besten zwei Normalen miteinander kombiniert, gibt es hier mit Vor- und Nachteilen der einzelnen Berechnungen: http://blog.selfshadow.com/publications/blending-in-detail/

Alle Änderungen zusammengeworfen und bereitgestellt unter http://www.mission-on-mars.com/blog/example/tile9/512/32/2/100 ergibt nun diese Ausgabe:

Die Struktur zwischen den Grid-Tiles ist sehr viel detaillierter – die Rechteck-Struktur ist allerdings noch sehr gut zu erkennen. Das passiert durch die Kmbination aus Vektor- und Map-Normalen. Stelle ich die Vektornormale auf

erhalte ich:

Und damit komme ich einer Marslandschaft wieder ein Stück näher.

Revision 67

Android

Weiterführende Links

Im nächsten Schritt kümmere ich mich um stark verzerrte Bereiche in der Highmap. Da liegt noch Potential für Verbesserungen.

Schreibe einen Kommentar

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