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
Ihr Szenenbaum wird in etwa so aussehen:
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.
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:
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:
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.