Projektziel: In FlightGear sah das Wasser bei mir oft grün aus, mal in Seen, mal im Meer. Das fiel besonders
auf, seit daneben echte Luftbilder liegen. Dahinter stecken zwei getrennte Ursachen, und beide lassen sich im Shader
beheben. Unterwegs habe ich erst falsch gelegen und dann falsch verglichen, auch das steht hier.
Bild 1 - Ausgangslage: Der See bei Leipzig ist dunkelgrün
Bild 2 - Derselbe See mit fester Wassertiefe
Ursache 1: Seen stehen auf einer Weltkarte
Der Wasser-Shader water-ALS-high.frag mischt flaches Wasser mit einer Bodenfarbe. Beide Werte kommen aus
groben Weltkarten:
vec4 depthTexel = texture2D(topo_map, TopoUV);
shallowness = depthTexel.r;
...
vec4 colorTexel = texture2D(water_colormap, TopoUV);
floorColour = colorTexel.rgb;
...
refl.rgb = mix(refl.rgb, 0.65 * floorColour, floorMixFactor);
Ein kleiner See liegt auf einer so groben Karte offenbar noch auf Land, also kommt Grün dazu. Für Binnengewässer gibt es
aber schon die passenden Schalter in Effects/water-inland.eff:
<use_specified_water_shallowness type="int">1</use_specified_water_shallowness>
<water_shallowness type="float">0.3</water_shallowness>
Der Wert 0,3 ist nicht beliebig: Darunter wird das Wasser dunkler, darüber kommt die Bodenfarbe zurück. Genau hier fällt sie
ganz weg, und die Helligkeit bleibt voll.
Ursache 2: Tiefe Sonne
Danach war das Wasser beim Shuttle-Start am Kennedy Space Center trotzdem grün, diesmal auf einer großen Fläche. Erst
dachte ich, die Fläche zähle als Meer und meine Korrektur erreiche sie nicht. Eine feste Tiefe auch fürs Meer machte das
Wasser aber nur dunkler. Der Vergleich derselben Stelle zu verschiedenen Uhrzeiten brachte die Antwort:
| Zeit (31.10., Florida) | Mittlere Farbe des Wassers (R / G / B) | Eindruck |
| 12:00 GMT, tiefe Sonne | 52 / 69 / 49 | grün |
| 14:00 GMT | 69 / 101 / 106 | blau |
| 17:00 GMT | 69 / 101 / 106 | blau |
| 22:00 GMT, tiefe Sonne | 54 / 77 / 65 | grünlich |
Es liegt also am Sonnenstand. Im Vertex-Shader wird das Licht je Farbkanal einzeln berechnet, und bei tiefer Sonne fällt Blau
am stärksten ab. Das ist als warmes Morgen- und Abendlicht gedacht und passt für Land. Ausgerechnet aus den Formeln im Shader:
lightArg | Rot | Grün | Blau |
| 12 (Sonne hoch) | 0,93 | 0,94 | 0,87 |
| 4 | 0,77 | 0,62 | 0,31 |
| 0 | 0,60 | 0,26 | 0,03 |
Die Grundfarbe des Wassers ist aber 0,148 / 0,27 / 0,3, sie enthält kaum Rot. Der Shader multipliziert beides.
Das Licht liefert kein Blau, das Wasser kein Rot, und übrig bleibt Grün.
Die Korrektur macht das Licht vor der Multiplikation neutraler, nur für das Wasser:
float light_helligkeit = dot(ambient_light.rgb, vec3(0.3, 0.59, 0.11));
ambient_light.rgb = mix(ambient_light.rgb, vec3(light_helligkeit), 0.7);
finalColor *= vec4(ambient_light.rgb + secondary_light * light_distance_fading(dist), ambient_light.a);
Bild 3 - 12:00 GMT ohne Korrektur: 52 / 69 / 49
Bild 4 - Mit Korrektur: 49 / 68 / 65. Um 14:00 GMT bleibt es unverändert bei 69 / 101 / 106
Die falsche Gegenprobe
Um zu sehen, ob das auch ohne meine Änderungen auftritt, habe ich FlightGear mit einem zweiten --fg-root
aufs Original gerichtet. Die Farben waren exakt gleich, also hielt ich die Frage für geklärt. Aufgefallen ist
der Fehler erst an den Erdbildern, die im Test „ab Werk“ genauso scharf waren wie meine eigenen. Mein Starter setzte schon
ein --fg-root, und das gewann. Erst der Lauf mit einem wirklich anderen Starter zeigte echte Originalbilder.
Das Ergebnis blieb zum Glück gleich: Auch das Original ist bei tiefer Sonne grün (52 / 69 / 49).
Ist das ein Fehler in FlightGear?
Die Lichtkurven sehen nach Absicht aus, grünes Wasser eher nach einer Nebenwirkung. Belegen kann ich das nicht. Echtes Wasser
spiegelt bei flachem Blick vor allem den Himmel und wird dadurch nicht einfach grün. Mit der Korrektur wirkt das Wasser abends
auch etwas weniger warm, und geprüft habe ich sie bisher in Standbildern.
Selbst ausprobieren
Beides lässt sich einbauen, ohne die FlightGear-Dateien anzufassen, über ein Overlay. Die Anleitung und ein Skript dazu
stehen in der FlightGear-Doku.
Fazit
Gleiche Farbe, zwei Ursachen: einmal eine grobe Karte, einmal das Licht. Geholfen hat die einfachste Messung, dieselbe Stelle zu
zwei Uhrzeiten. Und eine Gegenprobe ist nur so viel wert wie die Prüfung, ob sie wirklich das Original getestet hat.