Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

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

Post-processing effects are shaders applied to a frame after Godot has rendered it. To apply a shader to a frame, create a CanvasLayer, and give it a ColorRect. Assign a new ShaderMaterial to the newly created ColorRect, and set the ColorRect's anchor preset to Full Rect:

Setting the anchor preset to Full Rect on the ColorRect node

Setting the anchor preset to Full Rect on the ColorRect node

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

Assign a new Shader to the ColorRect's ShaderMaterial. You can access the frame's texture and UV with a sampler2D using hint_screen_texture and the built-in SCREEN_UV uniforms.

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 less_than_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(less_than_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(less_than_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