Einfacher Shader für Punktlichter im Nebel

Ich brauchte einen einfachen und schnellen Shader, um Nebel zu erzeugen, der von Punktlichtquellen beleuchtet wird. Um es zu implementieren, habe ich den Effekt des Bildschirmbereichs geschrieben, dessen Ergebnisse unten gezeigt werden. Der Förderer ist fast so einfach wie bei normalen Punktquellen. Es erfordert keine Datenvolumenstrukturen, Ray Marching und kann problemlos an einen vorhandenen Lighting Shader angeschlossen werden.

Das wichtigste Prinzip ist, dass Sie das vom Nebel ausgehende Licht in geschlossener Form berechnen können, als ob es von einer Punktbeleuchtungsquelle beleuchtet wird. Meine Lösung bestand darin, die Formel und ihre Substitution im Shader zu finden.


Eine kleine Szene mit einem Raumschiff, das mit meiner Technik im Nebel gerendert wurde

Die Grundeinstellung

Nebelmodell


Der Shader macht einige Annahmen über den Nebel, mit dem wir arbeiten. Tatsächlich betrachtet er jedes Nebelfragment als eine kleine durchscheinende weiße Streufläche.

  • Der Shader schlägt vor, dass der Nebel das Licht gleichmäßig in alle Richtungen streut. Echter Nebel oder Rauch hat nicht immer diese Eigenschaft, aber dies ist eine gute Annäherung an das Bild, das wir anstreben.
  • Shader schlägt vor, dass alle Wellenlängen des Lichts auf die gleiche Weise mit Nebel interagieren. In der Realität ist dies oft nicht der Fall. Zum Beispiel macht Rayleigh-Streuung den Himmel blau und streut blaues Licht mehr als andere Wellenlängen.
  • Das vom Nebel ausgehende Licht variiert in Abhängigkeit vom umgekehrten Quadrat der Entfernung von der Lichtquelle zum Nebel. In Wirklichkeit passiert das nicht, aber es sieht normal aus. Es gibt viele Ressourcen, die erklären, wie Nebel die Beleuchtung tatsächlich streut, und ich bin sicher, dass Sie meine Methodik mit diesen Formeln ergänzen können.

Dennoch. Die Ergebnisse erscheinen auch bei Verwendung dieser Vereinfachungen plausibel.

Analytische Lösung


Es gebe ein infinitesimales Nebelfragment (stell dir einen kleinen Nebelwürfel vor). Dann sieht das von diesem Nebelfragment in meinem System ausgestrahlte Licht folgendermaßen aus:

light=1(distance from light to fog fragment)2


Diese Formel zeigt, dass das Licht, das von jedem Nebelfragment kommt, mit dem umgekehrten Quadrat seines Abstands zur Lichtquelle abnimmt, wie dies bei Licht der Fall ist, das von einer lichtstreuenden Oberfläche kommt.

Der Einfachheit halber schreiben wir die Gleichung neu:

d=distance from light to fog fragment


light=1d2


view linelight atxdx


Oder, wenn formeller:

L=light position


w=world fragment position


c=camera position


light arriving at camera=cw1|xL|2dx



Dieses Integral drückt genau das aus, was wir brauchen, aber seine Berechnung ist komplizierter als wir brauchen. Da alle Variablen im obigen Bild Vektoren mit drei Werten sind, müssen wir uns im Wesentlichen mit 12 Variablen befassen. Ich werde die meisten dieser Variablen durch eine einfache Neuparametrisierung eliminieren.

Definieren Sie einen neuen Raum namens " Lichtraum ".

  • Die x-Achse ist die Sichtlinie
  • Y-Achse für die Beleuchtung


Anstelle eines linearen Integrals im dreidimensionalen Raum führe ich jetzt einfach eine Integration entlang der X-Achse von der Kamera zu einem Fragment der Welt durch. Als nächstes müssen wir das Integral neu schreiben. Entfernung vom Punktx auf der x-Achse zur Lichtquelle ist h2+x2. Daher nimmt das Sichtlinienintegral die Form an

1h2+x2dx


Wenn Sie es manuell oder in Ihrem bevorzugten Computeralgebrasystem lösen, erhalten wir:

1h2+x2dx=tan1(xh)h


Das heißt, um die Beleuchtung für eine bestimmte Sichtlinie aus dem Nebel zu holen, berechne ich dieses Integral von der Kamera zu einem Fragment der Welt. Wenn die Kamera eingeschaltet istx=aund ein Fragment der Welt in x=bdann hat die Beleuchtung, die vom beleuchteten Nebel entlang der Sichtlinie in das Pixel eintritt, die Form:

ab1h2+x2dx=tan1(bh)htan1(ah)h


Gedanken zur Umsetzung


Ich habe es geschafft, diesen Shader ohne größere Änderungen in meine verzögerte Shader-Pipeline zu implementieren. Dazu mussten etwa zehn Zeilen GLSL-Code hinzugefügt werden. Wenn der Förderer bereits die diffuse + spiegelnde Beleuchtung mit Punktlichtquellen berechnet, sollte der Punktquellen-Shader bereits Zugriff auf die Kameraposition haben. die Lichtquelle und das aktuelle Pixel der Welt, und das ist alles, was Sie brauchen!

Die Verarbeitung mehrerer Lichtquellen ist sehr einfach. Es reicht aus, den Effekt der Lichtstreuung durch Nebel für jede Quelle einfach zusammenzufassen. Damit das System für mehrere Quellen effektiv ist, muss das Integral nur für Pixel berechnet werden, die so nahe an der Lichtquelle liegen, dass es zur visuell wahrnehmbaren Lichtmenge in der Szene beitragen kann. In einer Pipeline mit verzögertem Shader können Sie beispielsweise ein sphärisches Netz um eine Lichtquelle rendern, sodass der Shader nur die Auswirkungen des Lichts für Pixel in der Nähe dieser Quelle berechnet.

Ich fand heraus, dass der schwierigste Teil der Implementierung dieses Shaders die korrekte Position der Kamera und eines Fragmentes der Welt im Beleuchtungsraum ist, so dass wir das vereinfachte Integral verwenden können.

Ergebnisse



Erzeugen Sie mit wenig Nebelscheinwerfer Welten auf niedrigem Niveau


Wenn mehr Quellen vorhanden sind, wird der Effekt stärker


Wenn Sie auch Informationen über die Richtung der Lichtquellen verfolgen, können Sie im Nebel eine schöne, figürliche Beleuchtung erzeugen

Zusätzliche Lektüre


Einführung in die Lichtstreuung: Eine bildgebende Wissenschaftsperspektive

Ein praktisches analytisches Einzelstreumodell für die Echtzeitwiedergabe

Atmosphärische Streuung und volumetrischer Nebelalgorithmus Teil 1

All Articles