Die meisten technischen Künstler versuchen irgendwann in ihrer Karriere, plausible Reflexionen der Kaustik zu erzeugen. Wenn Sie ein Spieleentwickler sind, ist einer der Hauptgründe für das Lesen von Twitter der endlose Strom an Inspiration, den Sie daraus ziehen können. Vor einigen Tagen hat Florian Gelzenlichter (
kolyaTQ auf Twitter) ein GIF des in Unity mithilfe von Shadern erzeugten
Ätzeffekts veröffentlicht. Der Beitrag (unten dargestellt) gewann schnell 1,5 Tausend Likes, was ein aufrichtiges Interesse an dieser Art von Inhalten zeigt.
Obwohl ich mich normalerweise mehr für längere und technisch komplexe Artikelserien interessiere (zum Beispiel über
volumetrische atmosphärische Lichtstreuung [
Übersetzung auf Habré] und
inverse Kinematik [
erster und
zweiter Teil der Übersetzung auf Habré]), konnte ich der Versuchung nicht widerstehen, ein kurzes und niedliches Tutorial zu schreiben über die Auswirkungen von
Florian .
Am Ende dieses Artikels befindet sich ein Link zum Herunterladen des Unity-Pakets und aller erforderlichen Assets.
Was ist ätzend
Möglicherweise
kennen Sie das Konzept der
Kaustik nicht , obwohl Sie diesen Effekt täglich feststellen. Ätzmittel sind Lichtreflexionen, die durch gekrümmte Oberflächen verursacht werden. Im allgemeinen Fall kann sich jede gekrümmte Oberfläche wie eine Linse verhalten, die Licht an einigen Punkten fokussiert und an anderen streut. Die gebräuchlichsten Medien, die einen solchen Effekt erzielen, sind Glas und Wasser, die sogenannte
Ätzwellen erzeugen (siehe unten).
Ätzmittel können andere Formen annehmen. Ein Regenbogen ist beispielsweise ein optisches Phänomen, das auftritt, wenn Licht in Regentropfen gebrochen wird. Genau genommen ist es daher ätzend.
Anatomie der Wirkung
Ein erkennbares Merkmal von Ätzwellen ist die Art und Weise, wie sie sich bewegen. höchstwahrscheinlich hast du ihn gesehen, wenn du jemals auf den Boden des Pools geschaut hast. Die Wiederherstellung eines echten Ätzmittels ist sehr kostspielig, da viele Lichtstrahlen simuliert werden müssen.
Florian gelang es, einen plausiblen Effekt zu erzielen, beginnend mit einer einzigen ätzenden Textur. Um mein Tutorial zu erstellen, habe ich die unten gezeigte Textur aus
OpenGameArt verwendet .
Eine wichtige Eigenschaft, mit der dieser Effekt realisiert werden kann, ist, dass das oben gezeigte Ätzmuster
nahtlos ist . Dies bedeutet, dass Sie zwei Bilder nebeneinander platzieren können und es keine erkennbare Naht zwischen ihnen gibt. Da wir diesen Effekt auf großen Flächen nutzen möchten, ist es wichtig, dass wir die Möglichkeit haben, diese Textur ohne Risse zu dehnen, die die Illusion zerstören können.
Nachdem
Florian die Textur erhalten hat, schlägt er drei Schritte vor:
- Wenden Sie zweimal ein Ätzmuster auf die Oberfläche des Modells an, jedes Mal mit unterschiedlichen Größen und Geschwindigkeiten
- Mischen Sie zwei Muster mit dem
min
Operator - Separate RGB-Kanäle beim Sampling.
Mal sehen, wie Sie die einzelnen Schritte in Unity implementieren können.
Shader-Erstellung
Der erste Schritt besteht darin, einen neuen Shader zu erstellen. Da dieser Effekt wahrscheinlich in einem 3D-Spiel verwendet wird, das auch über eine echte Beleuchtung verfügt, ist es am besten, mit einem
Oberflächen-Shader zu beginnen . Oberflächen-Shader sind eine von vielen Arten von Shadern, die von Unity unterstützt werden (z. B.
Vertex- und Fragment-Shader für unbeleuchtete Materialien,
Screen-Shader für Nachbearbeitungseffekte und
Computational-Shader für Simulationen außerhalb des Bildschirms).
Der neue Surface Shader verfügt nur über wenige Funktionen. Um diesen Effekt zu erzielen, müssen wir Informationen an den Shader übertragen. Das erste ist die ätzende Textur. Zweitens ist dies der Parameter, der zum Skalieren und Versetzen verwendet wird.
Erstellen wir zwei
Shader-Eigenschaften :
Properties { ... [Header(Caustics)] _CausticsTex("Caustics (RGB)", 2D) = "white" {}
und die entsprechenden
Cg-Variablen :
sampler2D _CausticsTex; float4 _Caustics_ST;
Die Shader-Eigenschaften entsprechen den Feldern, die im Unity Material Inspector angezeigt werden. Die entsprechenden
Cg-Variablen sind die Werte selbst, die im Shader-Code verwendet werden können.
Wie Sie dem obigen Code
_Caustics_ST
ist
float4
,
float4
es enthält vier Werte. Wir werden sie verwenden, um die Probenahme der ätzenden Textur zu steuern. Nämlich:
_Caustics_ST.x
: Skala der ätzenden Textur entlang der X-Achse;_Caustics_ST.y
: Skala der ätzenden Textur entlang der Y-Achse;_Caustics_ST.z
: Verschiebung der ätzenden Textur entlang der X-Achse;_Caustics_ST.w
: Verschiebung der ätzenden Textur entlang der Y-Achse;
Warum heißt die Variable _Caustics_ST?Wenn Sie bereits ein wenig Erfahrung mit Shadern haben, haben Sie bereits andere Eigenschaften gesehen, die mit dem Suffix _ST
. In Unity kann _ST
verwendet werden, um zusätzliche Informationen darüber hinzuzufügen, wie die Textur abgetastet wird.
Wenn Sie beispielsweise die Cg-Variable _MainTex_ST
, können Sie damit die Größe und den Versatz _MainTex_ST
, wenn Sie eine Textur auf das Modell anwenden.
Normalerweise _ST
Variablen _ST
Eigenschaften, da sie automatisch im Inspektor angezeigt werden. In diesem speziellen Fall können wir uns jedoch nicht darauf verlassen, da wir die Textur zweimal abtasten müssen, jedes Mal mit einem anderen Maßstab und Versatz. In Zukunft müssen wir diese Variable in zwei verschiedene Variablen duplizieren.
Abtasttextur
Jeder
Oberflächen-Shader enthält eine Funktion, die üblicherweise als
surf
bezeichnet wird und zur Bestimmung der Farbe jedes gerenderten Pixels verwendet wird. Die "Standard"
surf
sieht folgendermaßen aus:
void surf (Input IN, inout SurfaceOutputStandard o) {
Die endgültige Farbe wird durch die Anzahl der Felder bestimmt, die der Shader initialisieren und in einer Struktur namens
SurfaceOutputStandard
. Wir müssen die
Albedo
ändern, die ungefähr der Farbe des von weißem Licht beleuchteten Objekts entspricht.
Im neu erstellten Surface Shader wird Albedo aus einer Textur namens
_MainTex
. Da der ätzende Effekt der vorhandenen Textur überlagert wird, müssen wir in
_CausticsTex
eine zusätzliche Abtastung der Textur
_CausticsTex
.
Mit einer als
UV-Overlay bezeichneten Technik können Sie nachvollziehen, welcher Teil der Textur abgetastet werden muss, je nachdem, welcher Teil der Geometrie gerendert werden muss. Dies erfolgt mit
uv_MainTex
- der Variablen
float2
, die an jedem Scheitelpunkt des 3D-Modells gespeichert ist und die Koordinate der Textur angibt.
Unsere Idee ist es,
_Caustics_ST
zu verwenden, um
_Caustics_ST
zu skalieren und zu
uv_MainTex
, um die ätzende Textur über das Modell zu strecken und zu bewegen.
void surf (Input IN, inout SurfaceOutputStandard o) {
Was passiert, wenn Albedo 1 überschreitet?Im obigen Code fügen wir zwei Texturen hinzu. Farbe ist normalerweise zwischen
vorher
Es gibt jedoch keine Garantie dafür, dass einige Werte dieses Intervall nicht überschreiten.
Bei älteren Shadern kann dies zu Problemen führen. Hier ist es eigentlich eine
Funktion . Wenn der Pixelfarbwert die Einheit überschreitet, bedeutet dies, dass sich sein Einfluss über seine Grenzen hinaus „ausbreiten“ und benachbarte Pixel beeinflussen sollte.
Dies ist genau das, was passiert, wenn sehr helle Spiegelreflexionen erhalten werden. Dieser Effekt sollte jedoch nicht nur von einem Surface Shader erzeugt werden. Damit der Effekt funktioniert, muss
HDR auf der Kamera eingeschaltet sein. Diese Eigenschaft steht für
High Dynamic Range ; Dadurch können Farbwerte überschritten werden
. Um eine übermäßige Menge an Farben auf benachbarten Pixeln zu verwischen, ist ein Nachbearbeitungseffekt erforderlich.
Unity verfügt über einen eigenen Nachbearbeitungsstapel mit einem Bloom-Filter, der genau das tut. Weitere
Informationen hierzu finden Sie im Unity-Blog:
PostFX v2 - Erstaunliche Grafik, aktualisiert .
Vorläufige Ergebnisse sind unten gezeigt:
Animierte Ätzmittel
Eines der wichtigsten Merkmale der Kaustik ist ihre Bewegung. Im Moment werden sie einfach statisch als zweite Textur auf die Oberfläche des Modells projiziert.
Die Animation von Materialien in Shadern kann mithilfe der Unity-Eigenschaft
_Time
implementiert werden. Es kann verwendet werden, um auf die aktuelle Spielzeit zuzugreifen, dh um den Gleichungen Zeit hinzuzufügen.
Am einfachsten ist es, die Textur einfach basierend auf der aktuellen Zeit zu versetzen.
Das Feld
_Time.y
enthält die aktuelle Spielzeit in
Sekunden . Wenn sich die Reflexion zu schnell bewegt, können Sie sie mit einem Faktor multiplizieren. Hierzu wird im oben dargestellten Code die Variable
_CausticsSpeed
vom Typ
float2
verwendet.
Möglicherweise müssen Sie die ätzende Textur in einer Sinuskurve für Ihre Zwecke vibrieren lassen. Es ist wichtig zu verstehen, dass es keinen Standardweg gibt, um den Effekt zu realisieren. Abhängig von Ihren Anforderungen können Sie ätzende Reflexionen ganz anders bewegen.
Die unten gezeigten Ergebnisse sind immer noch ziemlich mittelmäßig. Das ist normal: Wir haben noch viel zu tun, damit die Reflexionen schön aussehen.
Mehrfachabtastung
Der Effekt wird lebendig, wenn Sie die ätzende Textur nicht nur einmal, sondern zweimal abtasten. Wenn Sie sie übereinander legen und mit unterschiedlichen Geschwindigkeiten bewegen, ist das Ergebnis völlig unterschiedlich.
Zunächst duplizieren wir die Eigenschaften
_Caustics_ST
und
_CausticsSpeed
sodass die Samples der beiden Texturen unterschiedliche Maßstäbe, Verschiebungen und Geschwindigkeiten aufweisen:
[Header(Caustics)] _CausticsTex("Caustics (RGB)", 2D) = "white" {}
Nachdem wir nun zwei ätzende Proben haben, können diese mit dem
min
Operator gemischt werden. Wenn Sie nur den Durchschnittswert nehmen, ist das Ergebnis nicht sehr gut.
Eine so kleine Änderung macht einen großen Unterschied:
Um den Code schön zu halten, können Sie den ätzenden Abtastcode auch in Ihre eigene Funktion einbinden:
RGB-Trennung
Damit die ätzenden Reflexionen gut aussehen, müssen Sie den letzten Trick ausführen. Beim Durchlaufen einer Schicht wird Licht unterschiedlicher Wellenlänge unterschiedlich gebrochen. Dies bedeutet, dass sich das Licht bei der Bewegung durch Wasser in verschiedene Farben "aufteilen" kann.
Um diesen Effekt zu simulieren, können wir jede ätzende Probe in drei Teile unterteilen, einen für jeden Farbkanal. Durch Abtasten der roten, grünen und blauen Kanäle mit einer leichten Abweichung erhalten wir eine Farbfehlanpassung.
Beginnen wir mit dem Hinzufügen der Eigenschaft
_SplitRGB
, die die Stärke des
_SplitRGB
Effekts angibt:
Die Höhe des Versatzes der RGB-Kanäle kann beliebig gewählt werden, aber selbst mit diesem einfachen Versatz wird ein sehr überzeugendes Bild erhalten:
Fazit und Downloads
Wenn Sie lernen möchten, wie Sie nahtlose ätzende Texturen erstellen, sollten Sie den interessanten Artikel
Periodische ätzende Texturen lesen.
In der Zwischenzeit arbeitet
Florian weiter an seinem ätzenden Shader und hat einige interessante Verbesserungen vorgenommen, die sichtbar werden.
Ein vollständiges Paket für dieses Tutorial ist auf Patreon verfügbar. Es enthält alle erforderlichen Elemente, um diese Technik neu zu erstellen. Das Paket wurde aus Unity 2019.2 exportiert und erfordert Postprocessing Stack v2.