Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

Введение в шейдеры

Эта страница объясняет, что такое шейдеры, и даёт представление о том, как они работают в Godot. Подробную информацию о языке шейдеров движка можно найти в Язык шейдеров.

Шейдеры - это особый вид программ, которые работают на графических процессорах (GPU). Изначально они использовались для просчёта 3D-сцен, но сегодня могут делать гораздо больше. С их помощью можно управлять тем, как движок отрисовывает геометрию и пиксели на экране, что позволяет добиться самых разных эффектов.

Современные движки рендеринга, такие как Godot, рисуют всё с помощью шейдеров: видеокарты могут выполнять тысячи инструкций параллельно, что приводит к невероятной скорости рендеринга.

Однако из-за своей параллельной природы шейдеры обрабатывают информацию не так, как обычные программы. Код шейдера работает с каждой вершиной или пикселем в отдельности. Вы также не можете хранить данные между кадрами. В результате при работе с шейдерами вам придется писать код и думать иначе, чем в других языках программирования.

Предположим, вы хотите обновить все пиксели в текстуре до заданного цвета. На языке GDScript в коде будут использоваться циклы for:

for x in range(width):
  for y in range(height):
    set_color(x, y, some_color)

Ваш код уже является частью цикла в шейдере, поэтому соответствующий код будет выглядеть следующим образом.

void fragment() {
  COLOR = some_color;
}

Примечание

Видеокарта вызывает функцию fragment() один или несколько раз для каждого пикселя, который она должна нарисовать. Подробнее об этом ниже.

Шейдеры в Godot

Godot предоставляет язык шейдеров, основанный на популярном OpenGL Shading Language (GLSL), но упрощённый. Движок обрабатывает за вас часть работы по инициализации нижнего уровня, что упрощает написание сложных шейдеров.

В Godot шейдеры состоят из основных функций, называемых "процессорными функциями". Процессорные функции - это точка входа шейдера в программу. Существует семь различных функций процессора.

  1. Функция vertex() пробегает по всем вершинам сетки и задаёт их положение и некоторые другие переменные для каждой вершины. Используется в шейдерах canvas_item и spatial shaders.

  2. Функция fragment() выполняется для каждого пикселя, покрытого сеткой. Она использует значения, выводимые функцией vertex(), интерполированные между вершинами. Используется в шейдерах canvas_item shader и spatial shader.

  3. Функция light() выполняется для каждого пикселя и для каждого освещения. Она берёт переменные из функции fragment() и из предыдущих запусков. Используется в шейдерах canvas_item и spatial shaders.

  4. Функция start() запускается для каждой частицы в системе частиц один раз, когда частица впервые порождается. Используется в шейдерах particles shader.

  5. Функция process() выполняется для каждой частицы в системе частиц для каждого кадра. Используется в шейдерах particles shader.

  6. Функция sky() запускается для каждого пикселя в кубической карте сияния, когда необходимо обновить кубическую карту сияния, и для каждого пикселя на текущем экране. Используется в sky shaders.

  7. Функция fog() выполняется для каждого фрокселя в объемном буфере фрокселей тумана, который пересекается с FogVolume. Используется шейдерами fog shader.

Предупреждение

Функция light() не будет выполняться, если включен режим рендеринга vertex_lighting или если в настройках проекта включено Rendering > Quality > Shading > Force Vertex Shading. На мобильных платформах он включен по умолчанию.

Примечание

Godot также предоставляет пользователям API для написания полностью собственных GLSL-шейдеров. Более подробную информацию можно найти в Применение вычислительных шейдеров.

Типы шейдеров

Вместо того, чтобы предоставлять конфигурацию общего назначения для всех случаев использования (2D, 3D, частицы, небо, туман), вы должны указать тип шейдера, который вы пишете. Разные типы поддерживают различные режимы рендеринга, встроенные переменные и функции обработки.

В Godot все шейдеры должны указывать свой тип в первой строке, например, так:

shader_type spatial;

Ниже представлены доступные типы:

Режимы визуализации

Шейдеры имеют дополнительные режимы рендеринга, которые можно указать во второй строке после типа шейдера, например, так:

shader_type spatial;
render_mode unshaded, cull_disabled;

Режимы рендеринга изменяют способ применения шейдера Godot. Например, режим unshaded заставляет движок пропустить встроенную функцию обработки света.

Каждый тип шейдера имеет различные режимы рендеринга. Полный список режимов рендеринга см. в справке по каждому типу шейдера.

Вершинный процессор

Функция обработки vertex() вызывается один раз для каждой вершины в шейдерах spatial и canvas_item. В шейдерах particles она вызывается один раз для каждой частицы.

Каждая вершина в геометрии вашего мира имеет такие свойства, как положение и цвет. Функция изменяет эти значения и передает их в функцию fragment. Вы также можете использовать её для передачи дополнительных данных в функцию fragment с помощью varying.

По умолчанию Godot преобразует для вас информацию о вершинах, которая необходима для проецирования геометрии на экран. Вы можете использовать режимы рендеринга для самостоятельного преобразования данных; пример смотрите в Шейдер Spatial doc.

Фрагментный процессор

Функция обработки fragment() используется для установки параметров материала Godot на каждый пиксель. Этот код запускается на каждом видимом пикселе, который рисует объект или примитив. Он доступен только в шейдерах spatial, canvas_item и sky.

Стандартным использованием фрагментной функции является настройка свойств материала, которые будут использоваться для расчёта освещения. Например, вы должны установить значения для ROUGHNESS (шероховатости поверхности), RIM (контура света) или TRANSMISSION (пропускания света), которые сообщат световой функции, как свет реагирует на этот фрагмент. Это позволяет контролировать сложную последовательность процессов шейдинга без необходимости написания пользователем большого количества кода. Если вам не нужен этот встроенный функционал, вы можете игнорировать его и написать свою собственную функцию обработки света, и Godot её оптимизирует. Например, если вы не укажете значение для RIM, Godot не будет рассчитывать контурное освещение. Во время компиляции Godot проверяет, используется ли RIM; если нет, то он вырежет весь соответствующий код. Таким образом, вы не будете тратить вычисления на эффекты, которые не используете.

Световой процессор

Процессор light() также работает попиксельно, и он запускается один раз для каждого источника освещения, который влияет на объект. Он не запускается, если ни один источник освещения не влияет на объект. Он существует как функция, вызываемая внутри процессора fragment() и обычно оперирует свойствами материала, заданными в функции fragment().

Процессор light() работает в 2D иначе, чем в 3D; для описания того, как он работает в каждом из них, смотрите их документацию, Шейдеры CanvasItem и Шейдеры Spatial, соответственно.