Осталось символов: 2048
Комментариев больше нет


Материалы
В Godot любой узел, наследуемый от элемента Canvas, будет иметь слот Material в инспекторе.Входные данные
Входные данные называются униформой. Это могут быть простые числа, значения цвета, текстуры или матрицы. Редактор Godot позволяет нам оформить входные параметры таким образом, чтобы пользовательский интерфейс предоставлял нам удобный способ ввода соответствующих данных.Координаты вершин
В 2D изображение представляет собой прямоугольник (спрайт или текстурный прямоугольник), имеющий 4 угла (4 вершины). Значения координат основаны на размере текстуры изображения в пикселях. Середина изображения имеет координату 0,0, хотя там нет точки вершины. Воображаемые точки между вершинами интерполируются и могут использоваться в операциях в шейдере фрагментов.UV-координаты
В 2D мы используем изображения, а в 3D у нас есть текстуры, которые представляют собой файлы 2D изображений, определяющие цвет, глубину, нормали поверхности и т.д. Координаты точек на этих изображениях используют числа с плавающей запятой в диапазоне от 0 до 1.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
}
Сдвиг
Сдвиг - это то же самое, что наклон краев изображения. Для этого мы хотим сдвинуть координаты x в сторону на линейную величину, пропорциональную y. Следовательно, добавьте смещение y к x.shader_type canvas2D;
void vertex() {
VERTEX.x += VERTEX.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.;
}
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;
}
Фрагментный шейдер
Используя этот шейдер, мы можем влиять на внешний вид пикселей изображения. Мы можем изменять входную текстуру или полностью заменять ее сгенерированными значениями.Некоторые полезные встроенные значения:Преобразование цветного изображения в монохромное
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
}
Создание цветового градиента
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));
}
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));
}
Комментариев больше нет