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 можливість зчитування текстури з екрана. Якщо ви не знайомі з цією можливістю, вам слід спершу прочитати Screen Reading Shaders Tutorial.
Однопрохідна постобробка
Ефекти пост-обробки – це шейдери, що застосовуються до кадру після того, як 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;
}
Використовуючи наведений вище код, ви повинні отримати ефект розмиття на весь екран, як показано нижче.