Up to date

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

Benutzerdefinierte Nachbearbeitung

Einführung

Godot bietet von Haus aus viele Nachbearbeitungseffekte, einschließlich Bloom, DOF und SSAO, die in Environment und Post-Processing beschrieben sind. Für fortgeschrittene Anwendungsfälle können jedoch eigene Effekte erforderlich sein. Dieser Artikel erklärt, wie Sie Ihre eigenen benutzerdefinierten Effekte schreiben können.

Der einfachste Weg einen benutzerdefinierten Nachbearbeitungs-Shader zu implementieren, besteht darin, die in Godot integrierte Fähigkeit zum Lesen der Bildschirmtextur zu verwenden. Wenn Sie damit nicht vertraut sind, sollten Sie zuerst die Screen Reading-Shader Anleitung lesen.

Single Pass Post Processing

Nachbearbeitungseffekte sind Shader, die auf ein Bild angewendet werden, nachdem Godot es gerendert hat. Um einen Shader auf ein Frame anzuwenden, erstellen Sie einen CanvasLayer, und geben Sie ihm einen ColorRect. Weisen Sie ein neues ShaderMaterial dem neu erstellten ColorRect zu und setzen Sie das Layout des ColorRect auf "Vollständiges Rechteck".

Ihr Szenenbaum wird in etwa so aussehen:

../../_images/post_tree1.png

Bemerkung

Eine weitere, effizientere Methode ist die Verwendung eines BackBufferCopy, um einen Bereich des Bildschirms in einen Puffer zu kopieren und in einem Shader-Skript über einen sampler2D mit hint_screen_texture darauf zuzugreifen.

Bemerkung

Zum Zeitpunkt der Erstellung dieses Artikels unterstützt Godot nicht das gleichzeitige Rendern in mehrere Puffer. Ihr Post-Processing-Shader hat keinen Zugriff auf andere Render-Passes und Puffer, die nicht von Godot bereitgestellt werden (wie Tiefe oder Normalen/Rauheit). Sie haben nur Zugriff auf den gerenderten Frame und die Puffer, die von Godot als Sampler bereitgestellt werden.

Für diese Demo werden wir diesen Sprite eines Schafes verwenden.

../../_images/post_example1.png

Weisen Sie dem ShaderMaterial des ColorRect einen neuen Shader zu. Sie können auf die Textur und UV des Frames mit einem sampler2D zugreifen, indem Sie hint_screen_texture und die Built-in-SCREEN_UV-Uniforms benutzen.

Kopieren Sie den folgenden Code in Ihren Shader. Der folgende Code ist ein Hex-Pixelisierungs-Shader von arlez80,

shader_type canvas_item;

uniform vec2 size = vec2(32.0, 28.0);
// If you intend to read from mipmaps with `textureLod()` LOD values greater than `0.0`,
// use `filter_nearest_mipmap` instead. This shader doesn't require it.
uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;

void fragment() {
        vec2 norm_size = size * SCREEN_PIXEL_SIZE;
        bool half = mod(SCREEN_UV.y / 2.0, norm_size.y) / norm_size.y < 0.5;
        vec2 uv = SCREEN_UV + vec2(norm_size.x * 0.5 * float(half), 0.0);
        vec2 center_uv = floor(uv / norm_size) * norm_size;
        vec2 norm_uv = mod(uv, norm_size) / norm_size;
        center_uv += mix(vec2(0.0, 0.0),
                         mix(mix(vec2(norm_size.x, -norm_size.y),
                                 vec2(0.0, -norm_size.y),
                                 float(norm_uv.x < 0.5)),
                             mix(vec2(0.0, -norm_size.y),
                                 vec2(-norm_size.x, -norm_size.y),
                                 float(norm_uv.x < 0.5)),
                             float(half)),
                         float(norm_uv.y < 0.3333333) * float(norm_uv.y / 0.3333333 < (abs(norm_uv.x - 0.5) * 2.0)));

        COLOR = textureLod(screen_texture, center_uv, 0.0);
}

Das Schaf wird etwa so aussehen:

../../_images/post_example2.png

Multi Pass Post Processing

Einige Post Processing-Effekte wie Unschärfen sind ressourcenintensiv. Sie können viel schneller ausgeführt werden, wenn Sie sie in mehrere Durchgänge aufteilen. In einem Multi Pass-Material nimmt jeder Durchlauf das Ergebnis des vorherigen Durchlaufs als Eingabe und verarbeitet es.

Um einen Multi-Pass Post-Processing-Shader zu erzeugen, stapeln Sie CanvasLayer und ColorRect-Nodes. Im obigen Beispiel verwenden Sie ein CanvasLayer-Objekt, um einen Shader zu rendern, der das Frame der darunter liegenden Ebene verwendet. Abgesehen von der Struktur der Nodes sind die Schritte die gleichen wie beim Single Pass Post Processing-Shader.

Ihr Szenenbaum wird in etwa so aussehen:

../../_images/post_tree2.png

Als Beispiel könnten Sie einen Vollbild-Gaußschen Weichzeichner-Effekt schreiben, indem Sie die folgenden Code-Stücke an jeden der ColorRect-Nodes anhängen. Die Reihenfolge, in der Sie die Shader anwenden, hängt von der Position des CanvasLayer im Szenenbaum ab, höher bedeutet früher. Für diesen Blur-Shader spielt die Reihenfolge keine Rolle.

shader_type canvas_item;

uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;

// Blurs the screen in the X-direction.
void fragment() {
    vec3 col = texture(screen_texture, SCREEN_UV).xyz * 0.16;
    col += texture(screen_texture, SCREEN_UV + vec2(SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.15;
    col += texture(screen_texture, SCREEN_UV + vec2(-SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.15;
    col += texture(screen_texture, SCREEN_UV + vec2(2.0 * SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.12;
    col += texture(screen_texture, SCREEN_UV + vec2(2.0 * -SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.12;
    col += texture(screen_texture, SCREEN_UV + vec2(3.0 * SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.09;
    col += texture(screen_texture, SCREEN_UV + vec2(3.0 * -SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.09;
    col += texture(screen_texture, SCREEN_UV + vec2(4.0 * SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.05;
    col += texture(screen_texture, SCREEN_UV + vec2(4.0 * -SCREEN_PIXEL_SIZE.x, 0.0)).xyz * 0.05;
    COLOR.xyz = col;
}
shader_type canvas_item;

uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;

// Blurs the screen in the Y-direction.
void fragment() {
    vec3 col = texture(screen_texture, SCREEN_UV).xyz * 0.16;
    col += texture(screen_texture, SCREEN_UV + vec2(0.0, SCREEN_PIXEL_SIZE.y)).xyz * 0.15;
    col += texture(screen_texture, SCREEN_UV + vec2(0.0, -SCREEN_PIXEL_SIZE.y)).xyz * 0.15;
    col += texture(screen_texture, SCREEN_UV + vec2(0.0, 2.0 * SCREEN_PIXEL_SIZE.y)).xyz * 0.12;
    col += texture(screen_texture, SCREEN_UV + vec2(0.0, 2.0 * -SCREEN_PIXEL_SIZE.y)).xyz * 0.12;
    col += texture(screen_texture, SCREEN_UV + vec2(0.0, 3.0 * SCREEN_PIXEL_SIZE.y)).xyz * 0.09;
    col += texture(screen_texture, SCREEN_UV + vec2(0.0, 3.0 * -SCREEN_PIXEL_SIZE.y)).xyz * 0.09;
    col += texture(screen_texture, SCREEN_UV + vec2(0.0, 4.0 * SCREEN_PIXEL_SIZE.y)).xyz * 0.05;
    col += texture(screen_texture, SCREEN_UV + vec2(0.0, 4.0 * -SCREEN_PIXEL_SIZE.y)).xyz * 0.05;
    COLOR.xyz = col;
}

Wenn Sie den obigen Code verwenden, sollten Sie einen Unschärfeeffekt für den gesamten Bildschirm erhalten, wie unten dargestellt.

../../_images/post_example3.png