Mapping & Hammer

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

  1. Erstelle einen Brush, der das gesamte Wasservolumen ausfüllt, vom Grund bis zur Oberfläche.
  2. Belege den ganzen Brush mit tools/toolsnodraw.
  3. Gib nur der Oberseite ein Wassermaterial, zum Beispiel nature/water_canals_water2.
  4. Lass den Brush ein World-Brush. Binde ihn nicht an func_detail oder ein anderes Entity.
  5. Schließe das Becken mit soliden World-Brushes ein und setze ein water_lod_control in 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:

DarstellungReflexionBlick unter die OberflächeZusätzliche Render-Durchgänge
TeuerEchtzeitRefraktionzwei, für Reflexion und Refraktion
MittelCubemapRefraktioneiner
GünstigCubemapkeine Refraktionkeiner

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.

  1. Setzt das Material $forcecheap 1, ist das Wasser immer günstig. Ein Beispiel ist nature/water_canals_cheap001.
  2. Eine Echtzeit-Reflexion braucht eine $reflecttexture im Material und dazu entweder $forceexpensive 1 oder die Spielereinstellung r_waterforceexpensive 1. Die meisten mitgelieferten HL2-Wassermaterialien setzen $forceexpensive 1, auch nature/water_canals_water2.
  3. Ohne Echtzeit-Reflexion entscheidet die Entfernung. Ab der Enddistanz des water_lod_control wird 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.

KeyvalueName in HammerStandardwert
cheapwaterstartdistanceStart Transition to Cheap Water1000
cheapwaterenddistanceEnd Transition to Cheap Water2000

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

SymptomUrsacheLösung
Wasser unsichtbar oder nicht korrekt dargestelltLeak in der Map oder Wasser-Brush an ein Entity gebundenLeak schließen, Brush mit Tools → Move to World zurückholen
Wasser undurchsichtig oder mit fehlerhafter SpiegelungZweite Wasserhöhe im selben PVS, oder ein func_viscluster oder Areaportal kreuzt die WasseroberflächeHöhen trennen, func_viscluster und Areaportale von der Oberfläche fernhalten
Schwarze, lila-schwarz karierte oder zu helle SpiegelungCubemaps fehlen oder wurden nicht für den aktiven Modus gebautenv_cubemap setzen, buildcubemaps für LDR und HDR
Wasser sieht in der Ferne plötzlich anders ausWasser ohne Echtzeit-Reflexion wechselt ab der Enddistanz auf günstigDistanzen im water_lod_control erhöhen, Cubemaps bauen
**** leaked ****, Linie führt durchs WasserWasser als AußengrenzeSolide 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.