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