Wasser in Source-Maps: richtig bauen und Fehler beheben
Wasser in Source- und GMod-Maps: Aufbau des Wasser-Brushes, teures und günstiges Wasser, water_lod_control, Cubemaps und Lösungen für Darstellungsfehler.
Wasser ist in der Source Engine ein World-Brush, dessen Oberseite ein Wassermaterial trägt, während alle anderen Seiten tools/toolsnodraw bekommen. Dazu gehören ein water_lod_control, eine dichte Hülle aus soliden Brushes und env_cubemap-Entities für die günstige Darstellung. Falsch gerendert wird Wasser meist aus einem von vier Gründen: Der Brush hängt an einem Entity, die Map hat ein Leak, zwei Wasserflächen auf verschiedenen Höhen sind vom selben Ort aus sichtbar, oder die Cubemaps fehlen.
Wie ein Wasser-Brush aufgebaut ist
- Erstelle einen Brush, der das gesamte Wasservolumen ausfüllt, vom Grund bis zur Oberfläche.
- Belege den ganzen Brush mit
tools/toolsnodraw. - Gib nur der Oberseite ein Wassermaterial, zum Beispiel
nature/water_canals_water2. - Lass den Brush ein World-Brush. Binde ihn nicht an
func_detailoder ein anderes Entity. - Schließe das Becken mit soliden World-Brushes ein und setze ein
water_lod_controlin die Map.
Hinter diesen Regeln steckt ein Mechanismus. Wassermaterialien tragen den Parameter %compilewater 1. VBSP zerlegt daraufhin die Visleafs entlang der Wasseroberfläche und speichert zu jedem Wasservolumen genau eine Höhe. Deshalb muss die Oberseite waagerecht sein, und deshalb funktioniert das nur mit World-Brushes: Mit einem Wasser-Brush als func_detail schrieb GMods VBSP im Test gar kein Wasservolumen in die BSP (leafwaterdata 0).
Wasser ist außerdem nicht solide. Ersetzt ein Wasser-Brush eine Außenwand, meldet VBSP **** leaked ****. Wie du die undichte Stelle findest, steht in Map-Leak-Fehler beheben.
Die Seiten bleiben nodraw, weil sie sonst als Flächen kompiliert werden. Mit Wassermaterial auf allen sechs Seiten entstanden im Test 60 statt 40 Flächen. Die Ansicht von unten erzeugt VBSP selbst aus dem Parameter $bottommaterial des Wassermaterials.
Teures und günstiges Wasser
Dasselbe Wasser kann auf drei Arten gezeichnet werden:
| Darstellung | Reflexion | Blick unter die Oberfläche | Zusätzliche Render-Durchgänge |
|---|---|---|---|
| Teuer | Echtzeit | Refraktion | zwei, für Reflexion und Refraktion |
| Mittel | Cubemap | Refraktion | einer |
| Günstig | Cubemap | keine Refraktion | keiner |
Welche Variante gilt, entscheidet die Engine in jedem Bild neu. Das Wiki der Valve Developer Community (VDC) unterscheidet nur teuer und günstig, „mittel“ ist unser Name für den Zustand dazwischen. Die folgende Reihenfolge stammt aus dem veröffentlichten Client-Code des Source SDK 2013. GMod nutzt einen eigenen Engine-Zweig, Abweichungen im Detail sind möglich.
- Setzt das Material
$forcecheap 1, ist das Wasser immer günstig. Ein Beispiel istnature/water_canals_cheap001. - Eine Echtzeit-Reflexion braucht eine
$reflecttextureim Material und dazu entweder$forceexpensive 1oder die Spielereinstellungr_waterforceexpensive 1. Die meisten mitgelieferten HL2-Wassermaterialien setzen$forceexpensive 1, auchnature/water_canals_water2. - Ohne Echtzeit-Reflexion entscheidet die Entfernung. Ab der Enddistanz des
water_lod_controlwird günstig gezeichnet, darunter mit Refraktion und Cubemap.
Du legst die Darstellung also vor allem über die Wahl des Materials fest. Die Spiegelung über Cubemaps muss trotzdem immer funktionieren, weil mittleres und günstiges Wasser darauf zurückfallen. Teures Wasser zeichnet große Teile der Szene bis zu dreimal. Wie du solche Kosten misst, zeigt GMod-Map optimieren.
water_lod_control richtig einsetzen
Das Entity steuert für alle Wasserflächen der Map, ab welcher Entfernung zur Kamera auf günstiges Wasser gewechselt wird.
| Keyvalue | Name in Hammer | Standardwert |
|---|---|---|
cheapwaterstartdistance | Start Transition to Cheap Water | 1000 |
cheapwaterenddistance | End Transition to Cheap Water | 2000 |
Beide Werte sind Units. Zwischen Start und Ende blendet das Material weich über, sofern es den Proxy WaterLOD enthält, wie die mitgelieferten Wassermaterialien.
Fehlt das Entity, bricht der Compile nicht ab. VBSP legt eines mit den Standardwerten an und schreibt:
Water found with no water_lod_control entity, creating a default one.
Setze trotzdem selbst eines, damit du die Distanzen an deine Map anpassen kannst. Erwarte aber nicht zu viel: Bei Materialien mit Echtzeit-Reflexion greift die Distanz nach dem SDK-Code und dem VDC nicht.
Wasser auf verschiedenen Höhen
Das VDC nennt die Regel: Bei teurem Wasser darf es in einem PVS, also der Menge der von einem Ort aus sichtbaren Bereiche, nur eine Wasserhöhe geben. Der SDK-Code zeigt den Grund: Der Client ermittelt pro Bild ein einziges sichtbares Wasservolumen und rendert Reflexion und Refraktion für genau dessen Höhe. Eine zweite Fläche auf einer anderen Höhe bekommt dann Bilder, die für die falsche Ebene berechnet wurden. Wie das im Spiel genau aussieht, haben wir nicht getestet. Eine Warnung gibt es dafür nicht: Eine Testmap mit zwei Becken auf verschiedenen Höhen kompilierte ohne jede Meldung.
- Eine Höhe pro Sichtbereich. Trenne Becken auf unterschiedlichen Höhen durch World-Brushes, sodass sie nie im selben PVS liegen.
- Dieselbe Höhe verwenden. Die Regel betrifft nur unterschiedliche Höhen. Mehrere Becken auf gleicher Höhe teilen sich die Spiegelebene.
- Arten nicht mischen. Laut VDC dürfen sich auch teures und günstiges Wasser kein PVS teilen. Müssen zwei Höhen zusammen sichtbar bleiben, gib dem gesamten Wasser dort ein Material mit
$forcecheap 1. Es spiegelt über seine Cubemap.
Cubemaps, 3D-Skybox und Displacements
Cubemaps. Wassermaterialien enthalten $envmap env_cubemap. Mittleres und günstiges Wasser spiegeln damit das nächstgelegene env_cubemap. Setze mindestens eines in jeden Bereich mit Wasser und führe nach dem endgültigen Compile buildcubemaps aus. Bis dahin enthält die BSP nur einen Ersatz aus der Skybox-Textur. Den Ablauf beschreibt Cubemaps und Reflexionen beheben, die Grundlagen zu HDR stehen im Artikel zur Beleuchtung in der Source Engine.
3D-Skybox. Nach dem SDK-Code wird die 3D-Skybox in einem einzigen Durchgang gezeichnet, ohne eigene Reflexion und Refraktion. Verwende dort ein Material mit $forcecheap 1. Laut VDC funktioniert günstiges Wasser in der Skybox neben teurem Wasser in der Map. Die Höhe ergibt sich aus dem Maßstab, denn der sky_camera steht für den Ursprung der Hauptmap: Liegt das Wasser dort auf Z = 128 und hat der sky_camera die Scale 16, gehört die Oberfläche in der Skybox 8 Units über den sky_camera. Umgekehrt zeigt die Echtzeit-Reflexion der Hauptmap nach dem SDK-Code und dem VDC die 2D-Skybox und nicht die 3D-Skybox. Das VDC führt für CS:GO und Garry's Mod einen Material-Parameter $reflect3dskybox, der das ändern soll. Getestet haben wir ihn nicht. Mehr dazu in 3D-Skybox erstellen.
Displacements. Ein Ufer aus Displacements dichtet ebenso wenig ab wie das Wasser selbst. Führe den Wasser-Brush unter dem Gelände weiter und lege unter beides einen soliden World-Brush. Nodraw gehört nur dorthin, wo das Gelände ihn verdeckt: Das VDC warnt vor einem Schliereneffekt, wenn nodraw das Wasser abdichtet. Mehr dazu in Displacements in Hammer.
Typische Fehler und ihre Ursache
| Symptom | Ursache | Lösung |
|---|---|---|
| Wasser unsichtbar oder nicht korrekt dargestellt | Leak in der Map oder Wasser-Brush an ein Entity gebunden | Leak schließen, Brush mit Tools → Move to World zurückholen |
| Wasser undurchsichtig oder mit fehlerhafter Spiegelung | Zweite Wasserhöhe im selben PVS, oder ein func_viscluster oder Areaportal kreuzt die Wasseroberfläche | Höhen trennen, func_viscluster und Areaportale von der Oberfläche fernhalten |
| Schwarze, lila-schwarz karierte oder zu helle Spiegelung | Cubemaps fehlen oder wurden nicht für den aktiven Modus gebaut | env_cubemap setzen, buildcubemaps für LDR und HDR |
| Wasser sieht in der Ferne plötzlich anders aus | Wasser ohne Echtzeit-Reflexion wechselt ab der Enddistanz auf günstig | Distanzen im water_lod_control erhöhen, Cubemaps bauen |
**** leaked ****, Linie führt durchs Wasser | Wasser als Außengrenze | Solide World-Brushes um das Becken |
Verschwindet Wasser auf Distanz vollständig, gibt es keine einzelne dokumentierte Ursache. Prüfe dann zuerst, ob eine zweite Wasserhöhe sichtbar wird. Das Compile-Log kannst du zusätzlich im Map Scanner einfügen. Er erkennt in VBSP-, VVIS- und VRAD-Logs Ursachen, Folgefehler und passende Lösungswege.
Häufige Fragen
Kann der Wasserspiegel steigen oder sinken?
Ja, mit func_water_analog. Das Entity bewegt einen Wasser-Brush über die Inputs Open, Close und SetPosition. Der normale Wasser-Shader funktioniert dort nicht, weil er feste Visleafs braucht. Verwende ein Material wie nature/water_movingplane. Es spiegelt nur über die Cubemap.
Spiegelt Wasser auch Spieler und Props?
Nur wenn das Material $reflectentities 1 setzt oder der Spieler r_waterforcereflectentities 1 aktiviert hat. Sonst enthält die Echtzeit-Reflexion nur die Welt und den Himmel.
Was braucht ein eigenes Wassermaterial?
Mindestens %compilewater 1, $abovewater, $fogcolor, $bottommaterial und $envmap env_cubemap. Fehlen $abovewater oder $fogcolor, warnt der Shader in der Konsole. Fehlt $bottommaterial, warnt VBSP. Für den weichen Übergang auf Distanz kommt der Proxy WaterLOD dazu.