Game Engine Math

KWEngine, Teil 31: Nebel hinzufügen

Mit Nebel lassen sich Szenen deutlich atmosphärischer gestalten: Morgendunst über einer Wiese, Bodennebel zwischen Hochhäusern oder dichter Dunst in der Ferne. Die KWEngine berechnet den Nebel in einem eigenen Schritt, nachdem die Szene beleuchtet wurde. Dabei werden alle Objekte (und auch der Hintergrund) abhängig von ihrer Entfernung zur Kamera mit der Nebelfarbe vermischt. Eingestellt wird der Nebel vollständig über Methoden der Klasse World.

Globaler Nebel

Der einfachste Nebel besteht nur aus einer Farbe und einer Dichte. Beide werden in der Methode Prepare() der Welt gesetzt:

public class GameWorld : World
{
    public override void Prepare()
    {
        // Objekte, Kamera und Licht wie in den vorherigen Teilen hinzufügen ...

        // Hellgraue, leicht bläuliche Nebelfarbe (Rot, Grün und Blau jeweils von 0 bis 1):
        SetFogColor(0.75f, 0.8f, 0.85f);

        // Nebeldichte (0 = kein Nebel, maximal 1):
        SetFogDensity(0.03f);
    }
}

Solange die Dichte 0 beträgt (Standardwert), gibt es keinen Nebel und die Engine überspringt den Nebelschritt komplett. Die Dichte gibt an, wie viel Sicht pro Welteinheit verloren geht, und muss deshalb zur Größe der Szene passen. Als Faustregel gilt: Nach etwa 3 geteilt durch die Dichte Welteinheiten ist die Szene zu 95 % vernebelt.

  • Dichte 0.3: Nach etwa 10 Einheiten ist die Sicht fast weg.
  • Dichte 0.03: Nach etwa 100 Einheiten ist die Sicht fast weg.
  • Dichte 0.005: Nach etwa 600 Einheiten ist die Sicht fast weg.

Pixel ohne Objekt (also zum Beispiel der Himmel) liegen auf der Far-Plane der Kamera, also ganz am Ende der Sichtweite. Sie werden deshalb meist deutlich stärker vernebelt als die Objekte in der Szene.

Höhennebel

Echter Bodennebel ist unten dicht und wird nach oben hin dünner. Dieses Verhalten lässt sich mit SetFogHeight() einschalten:

// Basishöhe 0 (Y-Achse), mittlerer Falloff:
SetFogHeight(0f, 0.5f);

Der erste Parameter ist die Höhe auf der Y-Achse, auf der genau die mit SetFogDensity() eingestellte Dichte gilt. Darunter wird der Nebel dichter, darüber dünner. Der zweite Parameter (Falloff, 0 bis 10) legt fest, wie schnell der Nebel nach oben hin dünner wird: 0 bedeutet, dass der Nebel überall gleich dicht ist, 0.1 ergibt einen sanften Übergang und 1 eine flache Bodenschicht. Voraussetzung ist, dass die globale Dichte größer als 0 ist.

Hochhäuser im Bodennebel

Schwaden, wabernde Oberkante und Wind

Gleichmäßiger Nebel wirkt schnell künstlich. Mit zwei weiteren Methoden lässt sich der Nebel lebendiger gestalten:

// Höhennebel: Basishöhe 6, Falloff 0.4
SetFogHeight(6f, 0.4f);

// Schwaden: Stärke 1 (0 bis 1), Größe des Musters 80 Welteinheiten
SetFogNoise(1f, 80f);

// Oberkante des Höhennebels wabert um bis zu 4 Welteinheiten nach oben und unten
SetFogNoiseHeight(4f);
Vergleich in drei Schritten (SetFogHeight, + SetFogNoise, + SetFogNoiseHeight)

Das linke Bild zeigt nur den Höhennebel, im mittleren Bild kommen die Schwaden hinzu und im rechten Bild wabert zusätzlich die Oberkante des Nebels. Die Stärke der Schwaden reicht von 0 (gleichmäßiger Nebel) bis 1 (stellenweise fast nebelfrei, an anderen Stellen doppelt so dicht). Der Parameter size gibt an, nach wie vielen Welteinheiten sich das Muster wiederholt (Standardwert: 20). Einzelne Schwaden sind etwa ein Viertel davon groß. Die wabernde Oberkante wirkt nur zusammen mit einem Falloff größer als 0 und richtet sich ebenfalls nach dem Parameter size.

Soll sich der Nebel bewegen, kann zusätzlich ein Wind festgelegt werden:

// Windrichtung (wird normalisiert) und Geschwindigkeit in Welteinheiten pro Sekunde:
SetFogWind(1f, 0f, 0.5f, 2f);

Der Wind verschiebt die Schwaden und gilt für den gesamten Nebel. Die Schwaden verändern sich auch ohne Wind langsam. Die Bewegung richtet sich nach der Weltzeit und steht deshalb im Editor-Modus still. In der Qualitätsstufe Low werden keine Schwaden berechnet, die wabernde Oberkante bleibt aber erhalten.

Nebel-Boxen

Manchmal soll der Nebel nur an einer bestimmten Stelle liegen, zum Beispiel in einem Tal oder in einer Höhle. Dafür gibt es die Klasse FogVolume, eine quaderförmige Nebel-Box:

FogVolume tal = new FogVolume();
tal.Name = "Talnebel";
tal.SetPosition(0f, 1f, 0f);          // Mittelpunkt der Box
tal.SetScale(20f, 4f, 20f);           // Größe (Breite, Höhe, Tiefe)
tal.SetColor(0.8f, 0.85f, 0.9f);      // Nebelfarbe der Box
tal.SetDensity(0.2f);                 // Nebeldichte der Box (0 = kein Nebel)
tal.SetHeightFalloff(1f);             // Nebel wird vom Boden der Box nach oben hin dünner
tal.SetEdgeSoftness(3f);              // weicher Übergang an den Rändern (in Welteinheiten)
AddFogVolume(tal);

Eine neu erzeugte Box ist 1 x 1 x 1 Einheiten groß und liegt im Ursprung der Welt. Ihre Rotation kann mit SetRotation() (Winkel in Grad) verändert werden. Beim Höhenfalloff gilt: 0 bedeutet überall gleich dicht, 1 deutlich dünner werdend und 3 eine flache Bodenschicht. Ohne weiche Ränder (SetEdgeSoftness(0f)) endet der Nebel an einer harten Kante.

Der Nebel einer Box wird zum globalen Nebel der Welt addiert. Außerdem nutzt die Box dessen Schwaden (SetFogNoise()), wabernde Oberkante (SetFogNoiseHeight()) und Wind (SetFogWind()). Für die Dichte der Box gilt dieselbe Faustregel wie beim globalen Nebel. Pro Welt sind höchstens 16 Nebel-Boxen erlaubt. Weitere Boxen werden nicht hinzugefügt (ein Hinweis erscheint im Log).

Nebel-Boxen verwalten

Nebel-Boxen lassen sich wie andere Objekte über ihren Namen wiederfinden und auch wieder entfernen:

// Erste Box mit diesem Namen suchen (null, falls es keine gibt):
FogVolume v = GetFogVolumeByName("Talnebel");
if (v != null)
{
    v.SetDensity(0.1f);       // Nebel in dieser Box dünner machen
    // RemoveFogVolume(v);    // alternativ: Box aus der Welt entfernen
}

int anzahl = GetFogVolumeCount();                  // aktuelle Anzahl der Boxen
List<FogVolume> alle = GetFogVolumes();            // Kopie der Liste aller Boxen
List<FogVolume> treffer = GetFogVolumesByName("Tal"); // alle Boxen, deren Name "Tal" enthält

Die aktuellen Einstellungen der Welt lassen sich über die Properties IsFogEnabled, FogColor, FogDensity, FogHeight und FogHeightFalloff abfragen.


Beitrag veröffentlicht

in

von

Schlagwörter:

Kommentare

Schreibe einen Kommentar

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

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre, wie deine Kommentardaten verarbeitet werden.