Основы HLSL

Начинаю перевод цикла уроков по шейдерам в Unity3d. Это первая статья цикла.

Введение.

Шейдеры Unity записываются в пользовательской среде под названием Shaderlab. С ее помощью можно настроить много параметров материала, который будет использовать наш шейдер. Внутри файла Shaderlab мы также объявим большую часть логики шейдера в HLSL. Поскольку Shaderlab - это просто способ установить некоторые параметры в материале, довольно легко научиться использовать его. HLSL немного сложнее, поэтому я объясню некоторые из его основ. Несмотря на то, что я стараюсь объяснить все в этом уроке, я, к сожалению, не могу объяснить каждый базовый принцип программирования, поэтому я рекомендую вам изучить C#, прежде чем возвращаться к шейдерам.
Т.к. это первый урок в этой серии, я попытался сделать его максимально простым. Если у меня это не получилось, и я предположил, что вы знаете о шейдерах, которых у вас нет, свяжитесь со мной. В этом случае я исправлю урок, чтобы он был более доступным. Если информация в этом уроке понятна, но у вас есть трудности с пониманием концепций, потому что все это немного «теоретично», не стесняйтесь перейти к следующим урокам, в которых мы будем использовать изученный в этом уроке концепции на практике, что сделает вещи более ясными.

Переменные.

HLSL - это статически типизированный язык. Это означает, что каждая переменная имеет определенный тип данных, который должен быть явно указан и не может измениться. Я быстро опишу некоторые типы здесь. Если вам нужна дополнительная информация, вы можете посмотреть эту страницу документации Unity: https://docs.unity3d.com/Manual/SL-DataTypesAndPrecision.html

Скалярные типы.

Простейшими типами переменных являются скалярные числа, они имеют одно числовое значение. В HLSL существует несколько типов скалярных чисел. Выбор более низкой точности может улучшить производительность ваших шейдеров, но современные графические карты довольно быстры, поэтому различия будут небольшими. Я часто использую float в своих шейдерах, где достаточно half или fixed переменных, поэтому используйте собственный выбор и не переусердствуйте.
  • Integer. Целые числа не имеют дробной части. Они гораздо менее распространены в графическом программировании и особенно в шейдерах, чем числа с дробными частями, но они по-прежнему часто полезны, например, как индексы, когда мы работаем с массивами.
  • Fixed. Числа с фиксированной точкой - это числа с наименьшей точностью в шейдерах. Они могут содержать значения от -2 до +2 и всегда иметь 256 шагов между соседними значениями. Они отлично подходят для цветов, потому что цвета также часто сохраняются только в 256 шагах на канал цвета.
  • Half. Числа с половинной точностью могут иметь практически любое значение, но они теряют точность, а дальше - значение 0. Значения половины точности отлично подходят для хранения цветов, которые требуют большего диапазона / точности (если мы будем отображать цвета HDR, мы должны использовать половину) или для хранения коротких векторов, таких как нормали.
  • Float. Числа с плавающей запятой технически имеют двойную точность half чисел, это означает, что они более точны, особенно для больших чисел. Обычно они используются для хранения позиций.

int integer = 3;                   //Число без дробной части
fixed fixed_point = 0.5;           //Число с фиксированной точкой между -2 and 2
half low_precision = 3.14;         //Число с низкой точностью
float high_precision = 14.321;     //Число с высокой точностью

Векторные типы.

Есть векторные значения, основанные на скалярных. С векторными типами мы можем представлять такие вещи, как цвета, позиции и направления, которые имеют несколько значений в переменной. Чтобы объявить их в HLSL, мы просто напишем количество измерений, которые нам нужны, в конце типа. Так мы получаем такие типы, как float2, int3, half4 и т. д. (Обратите внимание, что максимум здесь 4 измерения, для большего их числа вам нужно использовать массивы, но мы не будем использовать их здесь). Вы можете получить доступ к различным компонентам векторов через xyz и w или rgb a.
Первый набор предназначен для представления компонентов векторов, а второй набор предназначен для отображения красного, зеленого, синего и альфа-каналов цвета, но мы можем использовать их взаимозаменяемо. Мы также можем использовать более одного из компонентов для переупорядочения компонентов, что называются swizzling.

fixed4 color = fixed4(1, 0.67, 0.73, 1);
float3 position = float3(1, 1, 0);
float2 textureCoordinates = float2(0.5, 0.5);

position.xy = position.yx; //меняем местами два первых компонента позиции

Типы матриц.

Также существуют типы матриц, которые основываются на векторе векторов. Они часто используются для поворота, перемещения и масштабирования векторов определенным образом, умножая матрицу на вектор. Вы можете создать матрицы, записав [размер 1]; x [размер 2]; за скалярным типом. В 3d-графике нам нужна матрица 3x3 для поворота и масштабирования матрицы или матрицы 4x4 для ее перемещения.
float4x4 transformMatrix3d;      //Матрица, которой можно масштабировать,
                                //поворачивать и перемещать вектор
 
float2x2 rotationMatrix2d = {   // Матрица, которой можно масштабировать
                                //и поворачивать 2d вектор но не перемещать его
        0, 1,
        -1, 0
    };

//Когда мы умножаем на матрицу, мы используем 4d вектор, 
//4-й компонент используется только для того, чтобы сделать возможным перенос
//вектора через умножение на матрицу
float4 position;

//Поворачиваем, масштабируем и перемещаем позицию умножая матрицу на вектор
//(Порядок сомножителей ВАЖЕН)
position = transformMatrix3d * position;

Samplers.

Существуют также образцы (samplers), которые используются для чтения из текстур. При чтении из samplers текстура имеет координаты от [0,0]; до [1,1], 0,0 - нижний левый угол, а 1,1 - верхний правый угол текстуры.

sampler2d texture; //В большинстве случаев мы используем 2d текстуры, но можно
//передать в шейдер 3d samplers.

//В большинстве случаев мы читаем из samplers функцией tex2d
//которая берет позицию в sample из второго аргумента.
float4 color = tex2D(texture, coordinates);

Структуры.

Наконец, существуют структуры, настраиваемые типы данных, которые могут содержать несколько других типов данных. Мы можем представлять источники света, входные данные и другие сложные данные с помощью структур. Чтобы использовать структуру, мы сначала должны ее определить, тогда мы можем использовать ее где-то еще.

//Определяем структуру
struct InputData {
 float4 position;
 fixed4 color;
 half4 normal;
};

//Создаем экземпляр и используем структуру
InputData data;
data.position = float4(1, 0, 0, 1);

Функции.

Хотя мы можем определять переменные за пределами функций, чтобы предоставлять информацию шейдеру, логические операции мы можем запускать только в функциях. Некоторые функции будут вызываться автоматически и будут возвращать значения, манипулируя с которыми мы будем обрабатывать вершин или цвета. Но мы также можем сами вызвать функции и использовать возвращаемые значения. Мы пишем тип переменной, возвращаемый функцией перед именем, возвращаемый тип также может быть void, что означает, что функция не возвращает значение. За именем функции мы помещаем аргументы, которые являются данными, которые получает функция. И в функции мы возвращаем значение, которое затем передается функции, которая вызвала эту функцию.

float add(float arg1, float arg2) {
 float sum = arg1 + arg2;
 return sum;
}

float function() {
 return add(3.5, 0.7);
}

Включаемые файлы.

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

#include “IncludeFile.cginc”

void function() {
 functionDeclaredInIncludeFile(3, variableInIncludeFile);
}


Оригинал: https://www.ronja-tutorials.com/2018/03/20/hlsl-basics.html


Переводчик Беляев В.А. ака seaman

Комментариев нет:

Отправить комментарий