So übertragen Sie einen Shader von einer Spiel-Engine auf Substance Painter

Mein Name ist Taras Uleisky, ich bin technischer Künstler im Plarium Kharkiv. Um die Grafik unseres Survival-Rollenspiels auf Mobilgeräten zu optimieren, haben wir unsere benutzerdefinierten Shader verwendet. Sie beinhalten die Verwendung eindeutiger Texturen und Karten, die Texturen und Karten in anderen gängigen Schattierungsmethoden nicht ähnlich sind. Infolgedessen ist 3D-Künstlern nicht ganz klar, wie diese Texturen für Assets im Spiel erstellt werden sollen. Um sofort zu sehen, wie das 3D-Modell in der Spiel-Engine in der Texturierungsphase aussehen wird, habe ich den Shader auf Substance Painter verschoben. Momentan gibt es in Substance Painter praktisch keine API-Materialien. Ich habe dieses Thema selbst studiert und mich daher entschlossen, meine eigenen Ideen zu teilen.



Unity Shader


Das Spiel verwendet Matcap Shading. Neben der üblichen Diff-Textur werden auch zwei vorgefertigte Matcap-Texturen auf den Shader übertragen. Sie werden mit jeweils zwei Masken interpoliert und verwischt. Infolgedessen wird die Matcap-Textur mit diffuser und gefälschter Blendung multipliziert, und auf dem Material sind Reflexionen zu sehen.



Das folgende Beispiel zeigt, wie Matcap in einem Shader-Diagramm implementiert ist. In diesem Fall werden zwei Matcap-Texturen in eine gepackt und in Kanäle unterteilt. Das heißt, Metall und Nichtmetall in den Kanälen R bzw. G.



Zwei Matcaps werden für ein Beispiel per Checker interpoliert.



Das Ergebnis ist eine gewisse Analogie zu Metall und Nichtmetall wie bei der PBR-Schattierung.

Wir wollten den Materialien Rauheit und Schmutz hinzufügen, um eine Art Rauheitsanalogon bei der PBR-Schattierung zu erzeugen. Dazu haben wir die Texturierungsmethode verwendet.Mip-Mapping . Eine Folge von Texturen erzeugt die sogenannte MIP-Pyramide mit einer Auflösung von maximal 1x1. Zum Beispiel: 1 × 1, 2 × 2, 4 × 4, 8 × 8, 16 × 16, 32 × 32, 64 × 64, 128 × 128. Jede dieser Texturen wird als MIP-Level bezeichnet. Um Pixel für Pixel Abnutzungserscheinungen im Shader basierend auf der Maske zu implementieren, müssen Sie den erforderlichen MIP-Pegel auswählen. Dies stellt sich folgendermaßen heraus: Wenn das Pixel auf der Maske schwarz ist, der maximale MIP-Pegel in Matcap ausgewählt ist und wenn die Pixelfarbe weiß ist, ist der MIP-Pegel 0.





Der Shader ermöglicht es daher, Reflexionen und Glanzlichter zu simulieren, leichte Rauheit und Abnutzungserscheinungen hinzuzufügen. Und das alles ohne die Verwendung von Cubemap, ohne komplexe Beleuchtungsberechnungen und andere Techniken, die die Leistung mobiler Geräte erheblich reduzieren.



Einrichten von Substance Painter zum Erstellen eines Shaders


Alle verfügbaren Shader in Substance Painter sind in GLSL geschrieben.
Um einen Shader für Substance Painter zu schreiben, verwende ich den kostenlosen VS-Code. Für die Hervorhebung der Syntax ist es besser, die Shader-Sprachunterstützung für die VS-Code-Erweiterung zu verwenden.



Es gibt nur sehr wenig Material über die API in Substance Painter, daher ist die Standarddokumentation in der Hilfe- / Dokumentations- / Shader-API von unschätzbarem Wert.



Das zweite, was beim Schreiben des Shaders hilft, sind die Standard-Shader in Substance Painter. Um sie zu finden, gehen Sie zu ... / Allegorithmic / SubstancePainter / resources / Shelf / Allegorithmic / Shader.

Versuchen wir, den einfachsten unbeleuchteten Shader zu schreiben, der die Grundfarbe anzeigt. Erstellen Sie zunächst eine Textdatei mit der Erweiterung .glsl und schreiben Sie einen so einfachen Shader. Vielleicht, obwohl nichts klar ist, werde ich die Struktur des Shaders in Substance Painter näher erläutern.



Erstellen Sie ein neues Projekt und ziehen Sie den Shader auf Ihre Shell. Im Import Ihre Ressourcen Dropdown-Liste, wählen Sie Projekt ‚project_name‘ .



Dies ist notwendig, damit alle Änderungen aktualisiert werden können.

Gehen Sie nun zu Fenster / Ansichten / Shader-Einstellungen und wählen Sie Ihren neuen Shader im angezeigten Fenster aus. Sie können die Suche verwenden.



Wenn Sie sehen, dass das gesamte Modell weiß ist und Sie die Grundfarbe darauf zeichnen können, haben Sie alles richtig gemacht. Jetzt können Sie das Projekt speichern und mit dem nächsten Abschnitt fortfahren.



Wenn das Modell rosa ist, liegt höchstwahrscheinlich ein Fehler im Shader vor - eine Benachrichtigung darüber wird in der Konsole angezeigt.

Erstellen eines Shaders in Substance Painter


Betrachten Sie die Struktur eines Shaders am Beispiel des zuvor beschriebenen unbeleuchteten Shaders.



Die Schattenmethode ist der grundlegende Teil des Shaders, ohne sie funktioniert sie nicht. Alles, was im Inneren beschrieben wird, kann auf einem 3D-Modell angezeigt werden. Alle endgültigen Berechnungen werden über die Funktion diffuseShadingOutput () ausgegeben .

Die Zeilen 3 und 4 erstellen einen Parameter bzw. eine Variable. Der Parameter ordnet den Basisfarbkanal der Variablen zu, in der die gemalte Textur gespeichert wird. Alle Parameter sind in der Hilfe angegeben , bei der Grundfarbe sollte alles wie im Beispiel angegeben werden. Zeile 8 legt die Textur in den UV-Koordinaten des 3D-Modells fest. Ich stelle fest, dass für die Textur mit Basisfarbe das Sparse Virtual Textures- System verwendet wird , da die Bibliothek mit der ersten Zeile verbunden istlib-sparce.glsl .

Sie können viele Implementierungen von Matcap finden, aber der Hauptpunkt ist, dass die Normalen des Modells auf die Kamera gerichtet sind und die Textur entlang der x- und y-Achse gedreht wird. Um die Normale in Richtung Kamera zu drehen, benötigen wir eine Ansichtsmatrix oder den Matrixtyp . Sie finden eine in dem oben genannten Zertifikat .



Dies sind also die gleichen deklarierten Namen wie im Fall der Grundfarbe. Jetzt müssen wir die Normalen des 3D-Modells erhalten.


Null als viertes Element des Vektors ist erforderlich.

Durch Multiplizieren einer Ansichtsmatrix mit einem Normalenvektor wird die Normalen zur Kamera erweitert.



Vergessen Sie nicht, dass beim Multiplizieren von Matrizen die Reihenfolge der Faktoren wichtig ist. Wenn Sie die Multiplikationsreihenfolge ändern, sind die Ergebnisse unterschiedlich.

Jetzt können Sie UV- Koordinaten aus viewNormal erstellen .



Es ist Zeit, die Matcap-Textur anzuschließen.



In diesem Fall erstellt der Parameter ein Texturfeld in der Shader-Oberfläche. Wenn das Projekt eine Textur mit dem Namen "Matcap_mip" hat, wird diese von Substance Painter automatisch verschärft.



Lassen Sie uns überprüfen, was passiert ist.



Hier wird die Textur von Matcap in neuen Koordinaten erweitert und am Ausgang mit der Grundfarbe multipliziert. Ich möchte darauf achten , dass die Matcap Textur durch die erweitert wird Textur () Funktion und Grundfarbe - durch die textureSparse () Funktion . Dies liegt daran, dass die über die Shader-Oberfläche angegebenen Texturen nicht vom Typ SamplerSparse sein können .

Das Ergebnis sollte ungefähr so ​​aussehen:



Fügen Sie nun eine Maske hinzu, die zwei Matcaps mischt. Fügen Sie der Einfachheit halber zwei Matcap'a in einer Textur hinzu und teilen Sie sie in Kanäle auf. Infolgedessen befinden sich zwei Matcap-Texturen in den Kanälen R bzw. G.

Es wird sich ungefähr so ​​herausstellen:



Beginnen wir damit, dem Shader eine Maske hinzuzufügen. Das Prinzip ähnelt dem Hinzufügen der Grundfarbe.



Es reicht aus, den Basisfarbenwert im Parameter durch user0 zu ersetzen.

Holen Sie sich nun den Maskenwert in den Pixel-Shader und mischen Sie die Matcap-Texturen.



Hier wird nur der R-Kanal in der Maske verwendet, da dieser schwarzweiß ist. Die beiden Matcap-Kanäle werden mit der Funktion mix () gemischt , einem Analogon von lerp in Unity.

Lassen Sie uns den Shader aktualisieren und benutzerdefinierte Kanäle in die Benutzeroberfläche einfügen. Gehen Sie dazu zu Fenster / Ansichten / Textur-Set-EinstellungenKlicken Sie im Fenster neben der Überschrift Kanäle auf das Pluszeichen und wählen Sie Benutzer0 aus der großen Liste aus.



Der Kanal kann beliebig aufgerufen werden.

Wenn Sie nun auf diesem Kanal zeichnen, können Sie sehen, wie die beiden Matcap-Texturen gemischt werden.



Der Shader für Unity verwendete auch normale Karten für Matcap, die aus einem High-Poly-Modell gebacken wurden. Versuchen wir, dasselbe in Substance Painter zu tun.

Um alle Operationen für Normalen zu verwenden, müssen Sie die entsprechende Bibliothek verbinden :



Jetzt verbinden wir die normalen Karten. In Substance Painter gibt es zwei davon: Eine wird durch Backen erhalten, und die zweite kann gezeichnet werden. Anhand



der Parameter können Sie erraten, dass channel_normal eine normale Karte ist, nach der Sie zeichnen können, und textur_normal- gebackene normale Karte. Ich stelle auch fest, dass der Variablenname textur_normal in die API eingebettet ist und Sie ihn nicht nach eigenem Ermessen benennen können.

Als nächstes entpacken Sie die Karten im Pixel-Shader:



Dann mischen wir die normalen Karten und Normalen, die sich auf den Scheitelpunkten des Modells befinden. Zu diesem Zweck gibt es in der oben verbundenen Bibliothek eine normalBlend () -Funktion .



Zuerst mischen wir die beiden normalen Karten und dann die normalen Normalen. Obwohl es nicht wirklich wichtig ist, in welcher Reihenfolge sie gemischt werden sollen.

Die Drehung der Normalen in Blickrichtung der Kamera sieht folgendermaßen aus:



Dann können Sie nichts ändern, alles bleibt gleich. Es sollte ungefähr so ​​sein:



Wie oben erwähnt, ist in diesem Fall eine Mip-Zuordnung erforderlich, um Abnutzungserscheinungen zu simulieren, ähnlich einer Rauheitskarte bei der PBR-Schattierung. Das Hauptproblem ist jedoch, dass die Pyramide aus Mip-Karten nicht für die Textur generiert wird, die von der Shader-Schnittstelle übertragen wird, und dementsprechend funktioniert die Methode textureLod () von glsl nicht. Man könnte in die andere Richtung gehen und die Matcap-Textur über den Benutzerkanal laden, wie dies beim Mischen von Matcaps der Fall war. Aber dann nimmt die Qualität der Textur stark ab und es erscheinen seltsame Artefakte.

Eine alternative Lösung besteht darin, eine Pyramide von MIP-Karten zu erstellenmanuell in Adobe Photoshop oder einem anderen ähnlichen Editor und wählen Sie dann die MIP-Stufe aus. Die Pyramide ist ganz einfach gebaut. Es ist notwendig, von der Größe der ursprünglichen Textur auszugehen - in meinem Fall ist es 256x256. Wir erstellen eine Datei mit einer Größe von 384 x 256 (384, weil 256 + 256/2) und reduzieren jetzt die ursprüngliche Textur um die Hälfte, bis sie ein Pixel groß ist. Alle Versionen reduzierter Texturen werden in aufsteigender Reihenfolge rechts von der ursprünglichen Textur platziert. Es sollte folgendermaßen aussehen:



Jetzt können Sie eine Funktion schreiben, die die Koordinaten jeder Textur in der Pyramide in Abhängigkeit von der Farbe jedes Pixels auf der Maske ermittelt.

Am einfachsten ist es, die UV-Koordinaten, die für jede Textur berechnet werden, in einem Array zu speichern. Die Größe des Arrays wird als log2 (Höhe) bestimmt.. Wir brauchen die ursprüngliche UV , also fügen wir sie dem Funktionsargument hinzu. Fügen Sie dem Funktionsargument eine Ebene hinzu, um zu bestimmen, welches Array-Element für ein bestimmtes Pixel verwendet werden soll .



Berechnen Sie nun UV für die ursprüngliche Textur, dh schneiden Sie diese zusätzlichen 128 Pixel in der Breite zu. Multiplizieren Sie dazu die x-Koordinate mit ⅔.



Um den Rest der Textur aus der Pyramide zu verwenden, müssen Sie Muster finden. Als wir die Pyramide aus den Texturen erstellten, konnten wir feststellen, dass die Textur jedes Mal um die Hälfte gegenüber der vorherigen Größe reduziert wurde. Das heißt, wie oft die Texturgröße abnimmt, können Sie bestimmen, indem Sie 2 auf die Leistung des MIP-Pegels erhöhen .



Es stellt sich heraus, dass die Textur um das 16-fache abnimmt, wenn Sie Stufe 4 auswählen. AlsUV- Koordinaten werden von 0 bis 1 bestimmt, dann muss die Größe normalisiert werden, dh 1 geteilt durch die Häufigkeit, mit der die Textur abgenommen hat, z. B. 1 geteilt durch 16.

Mit dem erhaltenen Wert der Größenvariablen können Sie die Koordinaten für einen bestimmten MIP-Pegel berechnen .



Die Größe von UV wird auf die gleiche Weise reduziert wie die Größe der Textur. An der x-Koordinate verschiebt sich die Textur immer um ⅔. Die y - Koordinatenverschiebung kann als die Summe aller Werte der definiert wird Größe variabel für jeden Level - Wert . Das heißt, wenn der Wert level = 1 ist , verschiebt sich uv in der y-Koordinate um 0 Pixel, und wenn level = 2 ist , ist die Verschiebung halb so hoch wie die Textur - 128 Pixel. Wenn Level = 3Dann stellt sich heraus, dass die Verschiebung 128 + 64 Pixel beträgt und so weiter. Die Summe aller Verschiebungen kann unter Verwendung des Zyklus erhalten werden.



Bei jeder Iteration addiert sich die Versatzvariable und verschiebt die Textur entlang der y-Achse um die gewünschte Anzahl von Pixeln. Der Schritt-für-Schritt-Algorithmus sieht ungefähr so ​​aus:



Der letzte Schritt besteht darin, einen Kanal anzuzeigen, der bei jedem Pixel den gewünschten Pegel auswählt . Wir haben das schon gemacht, nichts Neues.





Um die MIP-Ebene als Textur auszuwählen , multiplizieren Sie einfach die Länge des Arrays mit der Textur. Jetzt können Sie neue UV-Koordinaten über die gerade geschriebene Methode verbinden.



Vergessen Sie nicht, die Textur in den Typ int zu übersetzen, da dies jetzt ein Index für das Array ist.
Als Nächstes müssen Sie wie zuvor einen benutzerdefinierten Kanal in Substance Painter hinzufügen. Es sollte so aussehen:





Das einzige, was dem Shader fehlt, ist die Lichtquelle und die Fähigkeit, sie durch Drücken der Umschalttaste zu drehen. Dazu benötigen wir zunächst einen Parameter , der den Drehwinkel durch Drücken von Shift und die Rotationsmatrix erzeugt .





Wir platzieren die Lichtquelle zufällig und multiplizieren die Position mit der Rotationsmatrix.



Jetzt dreht sich die Lichtquelle durch Drücken der Umschalttaste um die y-Achse. Bisher ist dies jedoch nur ein Vektor, in dem die Position der Lichtquelle gespeichert ist. Es gibt gute Sachenwie man gerichtetes Licht in einen Shader implementiert. Wir werden uns auf ihn konzentrieren. Es bleibt uns überlassen, die Lichtrichtung und die Beleuchtung unseres Modells zu bestimmen.



Die Farbe des Schattens und die Farbe der Lichtquelle werden durch die Parameter eingestellt:



Die Farbparameter werden gemäß der oben berechneten Beleuchtung interpoliert.



Es wird folgendermaßen aussehen:



Mit diesen Parametern können Sie die Farbe des Schattens und die Farbe der Lichtquelle über die Substance Painter-Oberfläche anpassen.



Erstellen und konfigurieren Sie eine Voreinstellung


Wenn der Shader fertig ist, müssen Sie die Matcap-Textur und den Shader mit der Regaleinstellung importieren.



Wir entfernen alle nicht verwendeten Kanäle und fügen Benutzerkanäle hinzu: Die



Voreinstellung für den Export von Texturen sieht wie jede andere aus, außer dass unsere benutzerdefinierten Kanäle verwendet werden.



Wir erstellen eine Vorlage für alle Einstellungen, sodass beim Erstellen des Projekts sofort der gewünschte Shader zugewiesen und alle Texturkanäle konfiguriert werden. Gehen Sie dazu zu Datei / SaveAsTemplate und speichern Sie die Vorlage.



Wenn Sie jetzt ein neues Projekt erstellen, müssen Sie nichts konfigurieren - wählen Sie einfach die gewünschte Vorlage aus.



Was hast du bekommen


Ein technischer Künstler kann Spezialeffekte erstellen, Szenen anpassen und Renderprozesse optimieren. Ich wollte auch, dass die Rüstungs- und Waffenmodelle in Stormfall: Saga of Survival genau das sind, was 3D-Künstler beabsichtigten. Infolgedessen sieht das 3D-Modell in Substance Painter genauso aus wie in der Spiel-Engine.


3D-Modell in Substance Painter mit benutzerdefinierter Schattierung.


3D-Modell in Unity mit benutzerdefinierter Schattierung.

Ich hoffe, der Artikel war nützlich und hat Sie zu neuen Errungenschaften inspiriert!

All Articles