Ваш первый 2D-шейдер

Введение

Шейдеры — это специальные программы, выполняемые на графическом процессоре и используемые для рендеринга графики. Весь современный рендеринг выполняется с помощью шейдеров. Более подробное описание шейдеров см. в разделе What are shaders.

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

Примечание

Если у вас есть опыт написания шейдеров и вы просто ищете обзор того, как работают шейдеры в Godot, см. Shading Reference.

Настройка

CanvasItem shaders используются для отрисовки всех 2D-объектов в Godot, тогда как шейдеры Spatial используются для отрисовки всех 3D-объектов.

Чтобы использовать шейдер, его необходимо прикрепить к Material, который, в свою очередь, прикреплён к объекту. Материалы — это тип Resource. Чтобы отрисовать несколько объектов одним и тем же материалом, материал необходимо прикрепить к каждому объекту.

Все объекты, производные от CanvasItem, имеют свойство материала. Это включает в себя все GUI elements, Sprite2Ds, TileMapLayers, MeshInstance2Ds и т. д. Они также могут наследовать материал родительского элемента. Это может быть полезно, если у вас много узлов, для которых вы хотите использовать один и тот же материал.

Для начала создадим узел Sprite2D. Вы можете использовать любой CanvasItem, если он рисует на холсте, поэтому для этого урока мы будем использовать Sprite2D, так как это самый простой CanvasItem, с которого можно начать рисовать.

В инспекторе нажмите рядом с надписью"Texture" в месте с надписью "[empty]" и выберите "Load", затем выберите «icon.svg». Для новых проектов это значок Godot. Теперь он должен отображаться в области просмотра.

Затем в Инспекторе, в разделе CanvasItem, щёлкните рядом с "Material" и выберите "New ShaderMaterial". Это создаст новый ресурс "Material". Щёлкните по появившейся сфере. Godot в настоящее время не определяет, пишете ли вы CanvasItem Shader или Spatial Shader, и отображает предварительный просмотр результатов пространственных шейдеров. Поэтому вы видите результат работы Spatial Shader по умолчанию.

Примечание

Материалы, наследующие ресурс Material, такие как StandardMaterial3D и ParticleProcessMaterial, можно преобразовать в ShaderMaterial, а их существующие свойства будут преобразованы в соответствующий текстовый шейдер. Для этого щёлкните правой кнопкой мыши по материалу в доке "FileSystem" и выберите Convert to ShaderMaterial. Это также можно сделать, щёлкнув правой кнопкой мыши по любому свойству, содержащему ссылку на материал, в инспекторе.

Щёлкните рядом с надписью "Shader" и выберите "New Shader". Затем щёлкните по только что созданному шейдеру, и откроется редактор шейдеров. Теперь вы готовы приступить к написанию своего первого шейдера.

Ваш первый шейдер CanvasItem

В Godot все шейдеры начинаются со строки, указывающей тип шейдера. Формат следующий:

shader_type canvas_item;

Поскольку мы пишем шейдер CanvasItem, мы указываем canvas_item в первой строке. Весь наш код будет располагаться под этим объявлением.

Эта строка сообщает движку, какие встроенные переменные и функции вам предоставить.

В Godot вы можете переопределить три функции для управления работой шейдера: vertex, fragment и light. В этом руководстве вы напишете шейдер с vertex и fragment функциями. Функции light значительно сложнее vertex и fragment, поэтому здесь они рассматриваться не будут.

Ваша первая функция fragment

Функция fragment выполняется для каждого пикселя в Sprite2D и определяет, какой цвет должен быть у этого пикселя.

Они ограничены пикселями, охватываемыми Sprite2D, это значит, что вы не можете использовать их, например, для создания контура вокруг Sprite2D.

Самая простая функция fragment не делает ничего, кроме назначения одного цвета каждому пикселю.

Для этого мы записываем vec4 во встроенную переменную COLOR. vec4 — это сокращённая запись для построения вектора из 4 чисел. Подробнее о векторах см. в Руководстве по векторной математике. COLOR — это и входная переменная функции фрагмента, и её конечный результат.

void fragment(){
  COLOR = vec4(0.4, 0.6, 0.9, 1.0);
}
../../../_images/blue-box.png

Поздравляем! Готово. Вы успешно написали свой первый шейдер в Godot.

Теперь давайте усложним ситуацию.

Функция fragment принимает множество входных данных, которые можно использовать для вычисления COLOR. UV — один из них. UV-координаты указываются в вашем Sprite2D (без вашего ведома!) и сообщают шейдеру, откуда считывать данные из текстур для каждой части сетки.

В функции fragment вы можете только читать из UV, но вы можете использовать ее в других функциях или напрямую присваивать значения COLOR.

UV изменяется в пределах от 0 до 1 слева направо и сверху вниз.

../../../_images/iconuv.png
void fragment() {
  COLOR = vec4(UV, 0.5, 1.0);
}
../../../_images/UV.png

Использование встроенной TEXTURE

Функция fragment по умолчанию считывает заданную текстуру Sprite2D и отображает ее.

Если вы хотите настроить цвет в Sprite2D, вы можете вручную настроить цвет текстуры, как показано в коде ниже.

void fragment(){
  // This shader will result in a blue-tinted icon
  COLOR.b = 1.0;
}

Некоторые узлы, например, Sprite2D, имеют специальную переменную текстуры, к которой можно получить доступ в шейдере с помощью TEXTURE. Если вы хотите использовать текстуру Sprite2D для комбинирования с другими цветами, можно использовать UV с функцией texture для доступа к этой переменной. Используйте их для перерисовки Sprite2D с использованием текстуры.

void fragment(){
  COLOR = texture(TEXTURE, UV); // Read from texture again.
  COLOR.b = 1.0; //set blue channel to 1.0
}
../../../_images/blue-tex.png

Проверка ввода

Для передачи данных в шейдер используется единообразный ввод, который будет одинаковым во всем шейдере.

Вы можете использовать униформы, определив их в верхней части шейдера следующим образом:

uniform float size;

Дополнительную информацию об использовании см. в документе Shading Language doc.

Добавьте униформу для изменения количества синего в нашем Sprite2D.

uniform float blue = 1.0; // you can assign a default value to uniforms

void fragment(){
  COLOR = texture(TEXTURE, UV); // Read from texture
  COLOR.b = blue;
}

Теперь вы можете изменить интенсивность синего цвета в Sprite2D в редакторе. Вернитесь в Inspector, где вы создали шейдер. Вы увидите раздел "Shader Param". Разверните его, и вы увидите только что объявленную вами униформу. Если вы измените значение в редакторе, оно перезапишет значение по умолчанию, указанное в шейдере.

Взаимодействие с шейдерами из кода

Вы можете изменить униформу из кода, используя функцию set_shader_parameter(), которая вызывается для материального ресурса узла. В узле Sprite2D для установки униформы blue можно использовать следующий код.

var blue_value = 1.0
material.set_shader_parameter("blue", blue_value)

Обратите внимание, что название униформы — это строка. Строка должна точно соответствовать тому, как она написана в шейдере, включая орфографию и регистр.

Ваша первая vertex (вершина) функция

Теперь, когда у нас есть функция fragment, давайте напишем функцию vertex.

Используйте функцию vertex, чтобы вычислить, где на экране должна оказаться каждая vertex (вершина).

Самая важная переменная в функции vertex — VERTEX. Изначально она определяет координаты вершин в вашей модели, но вы также записываете в неё данные, чтобы определить, где именно эти вершины будут отображаться. VERTEX — это vec2, изначально представленный в локальном пространстве (т.е. не относительно камеры, области просмотра или родительских узлов).

Вы можете сместить вершины, напрямую добавляя VERTEX.

void vertex() {
  VERTEX += vec2(10.0, 0.0);
}

В сочетании со встроенной переменной TIME это может быть использовано для базовой анимации.

void vertex() {
  // Animate Sprite2D moving in big circle around its location
  VERTEX += vec2(cos(TIME)*100.0, sin(TIME)*100.0);
}

Заключение

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

Для вдохновения взгляните на некоторые более продвинутые руководства по шейдерам, а также посетите другие сайты, например Shadertoy и The Book of Shaders.