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...
Пользовательская пост-обработка
Введение
Godot предоставляет множество встроенных эффектов постобработки, включая Bloom, DOF и SSAO, которые описаны в документе Окружающая среда и постобработка. Однако для более сложных случаев могут потребоваться пользовательские эффекты. В этой статье объясняется, как создавать собственные пользовательские эффекты.
Самый простой способ реализовать собственный шейдер постобработки — использовать встроенную в Godot возможность чтения текстуры с экрана. Если вы не знакомы с этим, рекомендуем сначала прочитать Учебник по шейдерам для чтения с экрана.
Однопроходная постобработка
Эффекты постобработки — это шейдеры, применяемые к кадру после его рендеринга Godot. Чтобы применить шейдер к кадру, создайте CanvasLayer и присвойте ему ColorRect. Назначьте новый ShaderMaterial только что созданному ColorRect и установите для ColorRect якорный шаблон Full Rect:
Установка предустановки привязки на Full Rect на узле ColorRect
Ваше дерево сцен будет выглядеть примерно так:
Примечание
Другой более эффективный метод — использовать BackBufferCopy для копирования области экрана в буфер и доступа к ней в скрипте шейдера через sampler2D с использованием hint_screen_texture.
Примечание
На момент написания статьи Godot не поддерживает рендеринг в несколько буферов одновременно. Ваш шейдер постобработки не будет иметь доступа к другим проходам рендеринга и буферам, не предоставляемым Godot (например, к глубине или нормалям/шероховатости). Вам будет доступен только отрендеренный кадр и буферы, предоставляемые Godot в качестве сэмплеров.
Для этой демонстрации мы будем использовать Sprite овцы.
Назначьте новый Shader для ShaderMaterial объекта ColorRect. Доступ к текстуре и UV-координатам рамки можно получить с помощью sampler2D, используя hint_screen_texture и встроенные юниформы SCREEN_UV.
Скопируйте следующий код в свой шейдер. Этот код — шейдер шестнадцатеричной пикселизации от 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);
}
Овца будет выглядеть примерно так:
Многопроходная пост-обработка
Некоторые эффекты постобработки, такие как размытие, требуют больших ресурсов. Вы можете значительно ускорить их выполнение, разбив на несколько проходов. В многопроходном материале каждый проход принимает результат предыдущего прохода в качестве входных данных и обрабатывает его.
Для создания многопроходного шейдера постобработки узлы CanvasLayer и ColorRect объединяются в один. В приведённом выше примере объект CanvasLayer используется для рендеринга шейдера с использованием кадра на слое ниже. За исключением структуры узлов, шаги те же, что и для однопроходного шейдера постобработки.
Ваше дерево сцен будет выглядеть примерно так:
Например, вы можете реализовать полноэкранный эффект гауссова размытия, добавив следующие фрагменты кода к каждому узлу ColorRect. Порядок применения шейдеров зависит от положения CanvasLayer в дереве сцены: чем выше, тем быстрее. Для этого шейдера размытия порядок не имеет значения.
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;
}
Используя приведенный выше код, вы должны получить эффект размытия на весь экран, как показано ниже.