Изучение Шейдеров в Godot Engine

Шейдеры - это программы, написанные на языке шейдеров, которые очень быстро выполняются на GPU (графическом процессоре) вашего процессора Intel или на специальной видеокарте NVIDIA / AMD / MSI. Они принимают входные данные и влияют на отдельные пиксели изображения с точки зрения их положения на экране и их отображения по отношению к связанной с ними UV-текстуре (2D-изображению).
Шейдеры используются для создания визуальных эффектов путем изменения цвета и формы материала. В 2D шейдеры называются холст пункт шейдеров и 3D шейдеры называются пространственными шейдеры. Другим видом шейдеров является шейдер частиц.
В коде есть униформы для ввода параметров, Вариации для глобальных переменных, функция вершин для обработки геометрии, функция фрагментов для влияния на цвета и функция освещения.
Ключевая вещь, которую следует иметь в виду, заключается в том, что шейдеры не хранят данные между операциями в различных положениях вершинных точек и UV-координатах. Таким образом, вы не можете установить переменную, которая используется между точками, как вы можете сделать в GDScript.

Материалы

В Godot любой узел, наследуемый от элемента Canvas, будет иметь слот Material в инспекторе.
Увеличить Изображение
Изучение Шейдеров в Godot Engine
Мы можем создать новый материал шейдера, который сам имеет параметр шейдера. Для этого мы можем отредактировать код шейдера или создать его в визуальном редакторе.
Увеличить Изображение
Изучение Шейдеров в Godot Engine

Входные данные

Входные данные называются униформой. Это могут быть простые числа, значения цвета, текстуры или матрицы. Редактор Godot позволяет нам оформить входные параметры таким образом, чтобы пользовательский интерфейс предоставлял нам удобный способ ввода соответствующих данных.

Координаты вершин

В 2D изображение представляет собой прямоугольник (спрайт или текстурный прямоугольник), имеющий 4 угла (4 вершины). Значения координат основаны на размере текстуры изображения в пикселях. Середина изображения имеет координату 0,0, хотя там нет точки вершины. Воображаемые точки между вершинами интерполируются и могут использоваться в операциях в шейдере фрагментов.
Увеличить Изображение
Изучение Шейдеров в Godot Engine
3D сетка, определяет форму 3D-объекта с любым количеством вершин с координатами x, y, z на основе пикселей.
Увеличить Изображение
Изучение Шейдеров в Godot Engine

UV-координаты

В 2D мы используем изображения, а в 3D у нас есть текстуры, которые представляют собой файлы 2D изображений, определяющие цвет, глубину, нормали поверхности и т.д. Координаты точек на этих изображениях используют числа с плавающей запятой в диапазоне от 0 до 1.
Увеличить Изображение
Изучение Шейдеров в Godot Engine
Текстуры накладываются на поверхности 3D-объекта в соответствии с данными УФ-отображения, хранящимися в объектной модели.
Вот UV, подходящий для отображения граней на кубе. Обратите внимание, что некоторые области теряются, а части изображения искажаются так, что оно может вписываться в квадратную форму изображения.
Увеличить Изображение
Изучение Шейдеров в Godot Engine
Фрагментный шейдерИспользуя этот шейдер, мы можем влиять на внешний вид пикселей изображения. Мы можем изменять входную текстуру или полностью заменять ее сгенерированными значениями.
Некоторые полезные встроенные значения:
  • UV - положение текущего пикселя
  • ЦВЕТ - цвет текущего пикселя
  • ТЕКСТУРА - изображение спрайта
Давайте рассмотрим несколько примеров.
Преобразование цветного изображения в монохромное:
Согласно 2D-изображению, координаты в диапазоне от 0,0 до 1,1 сопоставляют точки изображения с областями на поверхностях куба.
С помощью шейдера мы могли бы ввести UV в виде однородной текстуры. Но мы также можем генерировать цвета с помощью кода, основанного на координате UV, координате вершины и времени.
В коде очень удобно иметь дело со значениями с плавающей запятой в диапазоне от нуля до единицы, потому что мы можем просто принять дробную часть числа за допустимое значение UV, а также использовать абсолютные значения функций синуса и косинуса. Кроме того, векторы могут быть нормализованы для соответствия ультрафиолетовому диапазону.

2D-преобразования

Изменяя значения вершинных точек, мы можем масштабировать, сдвигать и поворачивать 2D-изображение. Каждая точка передается вершинному шейдеру в виде 2D-вектора. Язык шейдинга - это не GDScript, а скорее C. Давайте покажем несколько примеров сценариев.
Чтобы настроить экспериментальную сцену, вы можете просто добавить спрайт в Node2D. Затем создайте новый материал шейдера в слоте Material на панели inspector. Затем отредактируйте новый сценарий шейдера.
Начните с добавления shader_type canvas_item;, чтобы указать тип шейдера, который мы будем создавать.
Затем мы добавим наш код в функцию вершинного шейдера. Доступны различные значения данных, называемые “встроенными”, нас интересует значение ВЕРШИНЫ. Это vec2, который содержит точки положения пикселя вершинной точки на холсте изображения.
Имейте в виду, что геометрия спрайта состоит из 2 треугольников и, следовательно, имеет только 4 вершины, которые можно перемещать. Таким образом, это ограничивает нас в том, насколько сильно мы можем сгибать и искажать его форму.

Масштабирование

shader_type canvas2D;
void vertex() { // The vertex shader function
    VERTEX *= 2.; // Transform the point coordinates
}
Здесь мы просто удваиваем значения координат точки, чтобы изображение масштабировалось на x2. Мы использовали сокращенный код для умножения, а не для записи VERTEX = VERTEX * 2.0.
Мы должны включить десятичную точку для числа, чтобы указать, что это значение с плавающей запятой, иначе оно будет интерпретировано как целое число. Кроме того, лишние нули не обязательно включать в код шейдера.

Сдвиг

Сдвиг - это то же самое, что наклон краев изображения. Для этого мы хотим сдвинуть координаты x в сторону на линейную величину, пропорциональную y. Следовательно, добавьте смещение y к x.
shader_type canvas2D;
void vertex() {
    VERTEX.x += VERTEX.y;
}
Здесь мы используем точечную нотацию для доступа к значениям x и y вектора и используем сокращенное дополнение.

Входные данные

Для динамического изменения вершинных точек мы можем использовать встроенное значение TIME, которое постоянно меняется, или предоставлять униформы. Униформы - это входные значения, доступные в инспекторе или через наши игровые скрипты.Мы можем взять дробную часть значения времени, чтобы получить переход от 0 к 1, повторяющийся каждую секунду. Чтобы изменить скорость, мы можем умножить TIME на коэффициент. Теперь мы можем применить это изменение к синусоидальной функции, чтобы получить синусоидальную волну, колеблющуюся между -1 и + 1. Затем масштабируйте и сдвигайте это значение, чтобы оно оставалось в диапазоне, скажем, от 0,5 до 1,0.Это можно использовать для создания эффекта пульсации спрайта следующим образом:
shader_type canvas2D;
void vertex() {
    float pi = 3.141592653589793;
    VERTEX *= .5 + (sin(fract(TIME) * pi * 2.) + 1.) / 4.;
}
Чтобы добавить скорость ввода, мы можем добавить форму следующим образом:
shader_type canvas2D;
uniform float rate = 1.0;
void vertex() {
    float pi = 3.141592653589793;
    VERTEX *= .5 + (sin(fract(TIME * rate) * pi * 2.) + 1.) / 4.;
}
Теперь это значение скорости будет отображаться как параметр шейдера в инспекторе и может быть изменено для изменения скорости эффекта пульсации. Чтобы изменить значение в GDScript, мы можем сделать это:
get_node("Sprite").get_material().set_shader_param("rate", 2.2)

Вращение

При вращении используется матрица преобразования. В нее вводится угол поворота, и точки вершин преобразуются матрицей.
shader_type canvas_item;
uniform float rate = 1.0;
void vertex() {
    float pi = 3.141592653589793;
    float a = fract(TIME * rate) * pi * 2.; // Rotate over full circle
    VERTEX = mat2(vec2(cos(a), sin(a)), vec2(-sin(a), cos(a))) * VERTEX;
}
Матрица 2X2 может быть построена из пары векторов vec2. Обратите внимание, что здесь мы не использовали краткую форму для умножения, потому что при матричном умножении порядок вычисления важен для получения ожидаемого результата.
Существуют также стандартные матрицы линейных преобразований для сдвига, масштаба, отражения и т.д.

Фрагментный шейдер

Используя этот шейдер, мы можем влиять на внешний вид пикселей изображения. Мы можем изменять входную текстуру или полностью заменять ее сгенерированными значениями.
Некоторые полезные встроенные значения:
  • UV - положение текущего пикселя
  • ЦВЕТ - цвет текущего пикселя
  • ТЕКСТУРА - изображение спрайта
Давайте рассмотрим несколько примеров.

Преобразование цветного изображения в монохромное

Увеличить Изображение
Изучение Шейдеров в Godot Engine
Этого можно достичь путем усреднения значений цвета RGB, чтобы получить равные выходные значения для вектора COLOR.rgb. Но для учета человеческого восприятия цвета мы можем применить средневзвешенное значение.
shader_type canvas_item;
void fragment() {
    COLOR = texture(TEXTURE, UV); // Get pixel color from the image texture
    float grey = .21 * COLOR.r + .71 * COLOR.g + .07 * COLOR.b;
    COLOR.rgb = vec3(grey); // Change the color value
}
Обратите внимание, что выше мы смогли задать всем 3 компонентам vec3 одно входное значение с плавающей точкой.

Создание цветового градиента

Увеличить Изображение
Изучение Шейдеров в Godot Engine
shader_type canvas_item;
void fragment() {
    COLOR = texture(TEXTURE, UV); // Get the sprite pixel rgb color
    COLOR.rg = UV.xy; // Map UV x,y values to COLOR red, green values
}

Передача значений между вершинным и фрагментарным шейдерами

В этом примере мы воспользуемся тем удобством, что начало координат вершины находится в центре спрайта, и передадим его значение из вершинного шейдера в фрагментный шейдер, используя переменную. Затем мы можем оценить длину вектора и применить наш эффект или нет.
shader_type canvas_item;
uniform float rate = 1.0;
varying vec2 v; // This is our varying value yet to be assigned
void vertex() { // Do some spinning
    float pi = 3.141592653589793;
    float a = fract(TIME * rate) * pi * 2.;
    VERTEX = mat2(vec2(cos(a), sin(a)), vec2(-sin(a), cos(a))) * VERTEX;
    v = VERTEX; // Here we assign the value to our varying
}
void fragment() {
    COLOR = texture(TEXTURE, UV);
    if (length(v) > 16.) // Do our shady stuff outside of a radius of 16px
        COLOR.rg = UV.xy;
}
В приведенном выше коде вы можете увидеть, как мы можем воздействовать только на определенные области изображения, используя условный оператор.

3D шейдеры

Из-за дополнительного измерения глубины вдоль оси z при работе с 3D-шейдерами необходимо учитывать больше. Например, некоторые грани объекта могут быть скрыты от глаз. Кроме того, UV-координаты связывают пиксели текстуры с положениями на гранях в зависимости от карты.
В Godot пространственный узел, такой как MeshInstance, имеет свойство mesh, которое определяет все вершинные точки, составляющие его проволочный каркас. Затем он оборачивается материалом. Этот материал обладает многими свойствами, включая альбедо (цвет или текстуру), карту нормалей и пропускание.
Надеюсь, позже я опубликую больше по большой теме шейдеров. И эта страница служит полезным введением в шейдеры в движке Godot.

Рисование линий

Значение UV может использоваться в качестве текущей точки в области текстуры. Итак, чтобы нарисовать линию, нам нужно отобразить некоторый цвет, когда UV находится очень близко к точке нашей линии или на ней, и не отображать цвет в другом месте.
Давайте проведем вертикальную линию примерно на одной трети пути вдоль оси x. Это соответствует UV.x == 0.3.
Мы можем рассчитать расстояние, на котором УФ находится от линии, с помощью: abs(UV.x - x)
Используя функцию smoothstep, мы можем выполнять интерполяцию между двумя значениями, где первое относится к темному, а второе - к яркому. Эта небольшая разница в значениях будет соответствовать половине толщины нашей линии, которая зависит от того, насколько далеко от линии находится UV-координаты.
Значения определяют, где находятся начальный и конечный края вывода шага от 0.0 до 1.0 в ответ на ввод 3-го параметра. Значение 3-го параметра пересекает этот диапазон, когда UV проходит над позицией нашей линии. Сглаживание смягчает края линии.
Итак, мы можем написать функцию для рисования линий следующим образом:
float line(vec2 pos, float x) {
    return smoothstep(0.01, 0.0, abs(pos.x - x));
}
x это то место, где мы хотим, чтобы отображалась строка, а pos.x это текущее положение шейдера фрагмента.
И код шейдера может выглядеть следующим образом:
shader_type canvas_item;
float line(vec2 pos, float x) {
    return smoothstep(0.01, 0.0, abs(pos.x - x));
}
void fragment() {
    COLOR.rgb = vec3(line(UV, 0.3));
}

Рисование кругов

Для линии, проведенной по кругу, мы можем сравнить значение UV с радиусом и смещением круга.Будет проще, если мы уберем смещения. Для UV, который находится в диапазоне от 0,0 до 1,1, мы можем преобразовать его так, чтобы исходить из центра. vec2 uv = UV - 0.5;
Итак, мы можем написать шейдер для рисования кругов следующим образом:
shader_type canvas_item;
float circle(vec2 pos, float radius) {
    return smoothstep(0.1, 0.0, abs(length(pos)-radius));
}
void fragment() {
    COLOR.rgb = vec3(circle(UV - 0.5, 0.4));
}

Повторяющиеся паттерны

В приведенных выше примерах мы сопоставляем значение UV-координаты с позицией. Чтобы сопоставить значение несколько раз, скажем, для создания сетки шаблонов, мы можем умножить UV на коэффициент и принять дробную часть за значение UV.
Для создания сетки из кругов:
shader_type canvas_item;
float circle(vec2 pos, float radius) {
    return smoothstep(0.1, 0.0, abs(length(pos)-radius));
}
void fragment() {
    vec2 uv = fract(UV * 8.0) - 0.5;
    COLOR.rgb = vec3(circle(uv, 0.4));
}
Вот и все друзья, на этом пока все, в следующем разделе мы подробнее изучим встроенные функции такие как sin(), cos(), abs(), pow() и так далее, первая часть уже здесь.
Увеличить Изображение
Изучение Шейдеров в Godot Engine
Теги:изучение шейдеров в godot engine,true

Комментариев больше нет

Осталось символов: 2048