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.
Checking the stable version of the documentation...
Pós-processamento personalizado
Introdução
O Godot oferece muitos efeitos de pós-processamento prontos para uso, incluindo Bloom, DOF e SSAO, que são descritos em Ambiente e pós-processamento. No entanto, casos de uso avançados podem exigir efeitos personalizados. Este artigo explica como escrever seus próprios efeitos personalizados.
A maneira mais fácil de implementar um shader de pós-processamento personalizado é usar a capacidade integrada do Godot de ler a textura da tela. Se você não está familiarizado com isso, deve ler o Screen Reading Shaders Tutorial primeiro.
Pós-processamento de passagem única
Efeitos de pós-processamento são shaders aplicados a um frame após o Godot tê-lo renderizado. Para aplicar um shader a um frame, crie um CanvasLayer e dê a ele um ColorRect. Atribua um novo ShaderMaterial ao recém-criado ColorRect e defina o preset de âncora do ColorRect para Full Rect:
Configurando o preset de âncora para Full Rect no nó ColorRect
Sua árvore de cena ficará parecida com isto:
Nota
Outro método mais eficiente é usar um BackBufferCopy para copiar uma região da tela para um buffer e acessá-la em um script de shader através de um sampler2D usando hint_screen_texture.
Nota
Até o momento da redação deste artigo, o Godot não suporta a renderização em múltiplos buffers ao mesmo tempo. Seu shader de pós-processamento não terá acesso a outros passes de renderização e buffers não expostos pelo Godot (como depth ou normal/roughness). Você tem apenas acesso ao frame renderizado e aos buffers expostos pelo Godot como samplers.
Para esta demonstração, usaremos este Sprite de uma ovelha.
Atribua um novo Shader ao ShaderMaterial do ColorRect. Você pode acessar a textura e o UV do frame com um sampler2D usando hint_screen_texture e os uniforms integrados do SCREEN_UV.
Copie o seguinte código para o seu shader. O código abaixo é um shader de pixelização hexagonal por 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);
}
A ovelha ficará parecida com isto:
Pós-processamento multipassagem
Alguns efeitos de pós-processamento, como desfoques (blurs), consomem muitos recursos. Você pode fazê-los rodar muito mais rápido se os dividir em múltiplos passes. Em um material multipass, cada passe recebe o resultado do passe anterior como entrada e o processa.
Para produzir um shader de pós-processamento multipass, você empilha nós CanvasLayer e ColorRect. No exemplo acima, você usa um objeto CanvasLayer para renderizar um shader usando o frame da camada abaixo. Fora a estrutura dos nós, os passos são os mesmos do shader de pós-processamento de passe único.
Sua árvore de cena ficará parecida com isto:
Como exemplo, você poderia escrever um efeito de desfoque gaussiano em tela cheia anexando os seguintes trechos de código a cada um dos nós ColorRect. A ordem em que você aplica os shaders depende da posição do CanvasLayer na árvore da cena: quanto mais alto, mais cedo. Para este shader de desfoque, a ordem não importa.
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;
}
Usando o código acima, você deve acabar com um efeito de desfoque em tela cheia como o abaixo.