Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

Einführung in Shader

Diese Seite erklärt, was Shader sind und gibt einen Überblick über ihre Funktionsweise in Godot. Für eine detaillierte Referenz der Shading-Sprache der Engine siehe Shader-Sprache.

Shader sind eine spezielle Art von Programmen, die auf Grafikprozessoren (GPUs) laufen. Ursprünglich dienten sie der Schattierung von 3D-Szenen, heute können sie aber weitaus mehr. Sie können damit steuern, wie die Engine Geometrie und Pixel auf dem Bildschirm zeichnet, sodass Sie alle möglichen Effekte erzielen können.

Moderne Rendering-Engines wie Godot zeichnen alles mit Shadern: Grafikkarten können Tausende von Anweisungen parallel ausführen, was zu einer unglaublichen Rendering-Geschwindigkeit führt.

Aufgrund ihrer parallelen Natur verarbeiten Shader Informationen jedoch nicht wie ein typisches Programm. Shader-Code wird isoliert auf jedem Vertex oder Pixel ausgeführt. Sie können auch keine Daten zwischen Frames speichern. Daher müssen Sie bei der Arbeit mit Shadern anders programmieren und denken als in anderen Programmiersprachen.

Angenommen, Sie möchten alle Pixel einer Textur in einer bestimmten Farbe aktualisieren. In GDScript würde Ihr Code for-Schleifen verwenden:

for x in range(width):
  for y in range(height):
    set_color(x, y, some_color)

Ihr Code ist bereits Teil einer Schleife in einem Shader, so dass der entsprechende Code wie folgt aussehen würde.

void fragment() {
  COLOR = some_color;
}

Bemerkung

Die Grafikkarte ruft die Funktion fragment() einmal oder mehrmals für jedes Pixel auf, das sie zeichnen muß. Mehr dazu weiter unten.

Shader in Godot

Godot bietet eine Shading-Sprache, die auf der beliebten OpenGL Shading Language (GLSL) basiert, jedoch vereinfacht ist. Die Engine übernimmt einen Teil der Initialisierungsarbeit auf unterer Ebene für Sie und erleichtert so das Schreiben komplexer Shader.

In Godot bestehen Shader aus Hauptfunktionen, die "Prozessorfunktionen" genannt werden. Prozessorfunktionen sind der Einstiegspunkt für Ihren Shader in das Programm. Es gibt sieben verschiedene Prozessorfunktionen.

  1. Die Funktion vertex() durchläuft alle Vertices im Mesh und setzt ihre Positionen und einige andere Variablen pro Vertex. Wird verwendet in canvas_item shaders und spatial shaders.

  2. Die Funktion fragment() wird für jedes vom Mesh abgedeckte Pixel ausgeführt. Sie benutzt Werte, die von der vertex()-Funktion ausgegeben werden, interpoliert zwischen den Vertices. Wird verwendet in canvas_item shaders und spatial shaders.

  3. Die Funktion light() wird für jedes Pixel und für jede Lichtquelle ausgeführt. Sie nimmt Variablen von der fragment()-Funktion und von ihren vorherigen Durchläufen. Sie wird verwendet in canvas_item shaders und spatial shaders.

  4. Die Funktion start() wird für jedes Partikel in einem Partikelsystem einmal ausgeführt, wenn das Partikel zum ersten Mal gespawnt wird. Wird verwendet in Partikel-Shadern.

  5. Die Funktion process() läuft für jedes Partikel in einem Partikelsystem für jedes Frame. Sie wird verwendet in Partikel-Shadern.

  6. Die Funktion sky() wird für jedes Pixel in der Radiance Cubemap ausgeführt, wenn die Radiance Cubemap aktualisiert werden muss, und für jedes Pixel auf dem aktuellen Bildschirm. Wird verwendet in Sky Shader.

  7. Die Funktion fog() wird für jedes Froxel im volumetrischen Nebel-Froxel-Puffer ausgeführt, das sich mit dem FogVolume schneidet. Wird verwendet von Fog-Shadern.

Warnung

Die Funktion light() wird nicht ausgeführt, wenn der Rendermodus vertex_lighting aktiviert ist, oder wenn Rendering > Qualität > Schattierung > Vertex-Schattierung erzwingen in den Projekteinstellungen aktiviert ist. Auf mobilen Plattformen ist es standardmäßig aktiviert.

Bemerkung

Godot stellt auch eine API zur Verfügung, mit der Benutzer völlig eigene GLSL-Shader schreiben können. Für weitere Informationen siehe Verwendung von Compute-Shadern.

Shader-Typen

Anstatt eine Allzweckkonfiguration für alle Verwendungszwecke (2D, 3D, Partikel, Himmel, Nebel) bereitzustellen, müssen Sie den Typ des Shaders angeben, den Sie schreiben. Verschiedene Typen unterstützen unterschiedliche Rendermodi, Built-in-Variablen und Prozessierungsfunktionen.

In Godot müssen alle Shader ihren Typ in der ersten Zeile angeben, etwa so:

shader_type spatial;

Hier sind die verfügbaren Typen:

Render-Modi

Shader haben optionale Rendermodi, die Sie in der zweiten Zeile nach dem Shader-Typ angeben können, etwa so:

shader_type spatial;
render_mode unshaded, cull_disabled;

Rendermodi verändern die Art und Weise, wie Godot den Shader anwendet. Zum Beispiel überspringt die Engine im Modus unshaded die eingebaute Lichtprozessorfunktion.

Jeder Shader-Typ hat verschiedene Render-Modi. Eine vollständige Liste der Rendermodi finden Sie in der Referenz für jeden Shadertyp.

Vertex-Prozessor

Die Prozessierungsfunktion vertex() wird in spatial und canvas_item-Shadern einmal für jeden Vertex aufgerufen. Bei Partikel-Shadern wird sie für jedes Partikel einmal aufgerufen.

Jeder Vertex in der Geometrie Ihrer Welt hat Eigenschaften, wie eine Position und eine Farbe. Die Funktion ändert diese Werte und übergibt sie an die Fragment-Funktion. Sie können damit auch zusätzliche Daten an die Fragmentfunktion senden, indem Sie Varyings verwenden.

Standardmäßig transformiert Godot die Vertex-Informationen für Sie, die notwendig sind, um die Geometrie auf den Bildschirm zu projizieren. Sie können Rendermodi verwenden, um die Daten selbst zu transformieren; ein Beispiel finden Sie in der Spatial-Shader-Dokumentation.

Fragment-Prozessor

Die Prozessierungsfunktion fragment() wird verwendet, um die Godot-Materialparameter pro Pixel einzustellen. Dieser Code läuft auf jedem sichtbaren Pixel, den das Objekt oder Primitiv zeichnet. Er ist nur in spatial, canvas_item und sky-Shadern verfügbar.

Die Standardanwendung der Fragmentfunktion ist die Einstellung von Materialeigenschaften, die zur Berechnung der Beleuchtung verwendet werden. Zum Beispiel würden Sie Werte für ROUGHNESS, RIM oder TRANSMISSION setzen, die der Lichtfunktion mitteilen, wie die Lichter auf dieses Fragment reagieren. Dies macht es möglich, eine komplexe Shading-Pipeline zu steuern, ohne dass der Benutzer viel Code schreiben muss. Wenn Sie diese eingebaute Funktionalität nicht benötigen, können Sie sie ignorieren und Ihre eigene Lichtverarbeitungsfunktion schreiben, und Godot wird sie wegoptimieren. Wenn Sie zum Beispiel keinen Wert für RIM schreiben, wird Godot keine Randbeleuchtung berechnen. Während des Kompilierens prüft Godot, ob RIM verwendet wird; wenn nicht, schneidet es den gesamten entsprechenden Code heraus. Daher werden Sie keine Berechnungen für Effekte verschwenden, die Sie nicht verwenden.

Licht-Prozessor

Der Licht() -Prozessor läuft ebenfalls pro Pixel, und er läuft einmal für jedes Licht, das auf das Objekt einwirkt. Er wird nicht ausgeführt, wenn keine Lichter das Objekt beeinflussen. Er existiert als eine Funktion, die innerhalb des Fragment()-Prozessors aufgerufen wird und arbeitet normalerweise mit den Materialeigenschaften, die innerhalb der Fragment() Funktion eingestellt wurden.

Der Licht()-Prozessor arbeitet in 2D anders als in 3D; für eine Beschreibung, wie er in beiden Fällen arbeitet, siehe deren Dokumentation, CanvasItem-Shader und Spatial-Shader.