Перейти к основному содержимому

Организация шейдеров материалов

Not (yet) implemented feature

Некоторые функции, описанные в настоящем документе, более не поддерживаются, либо начнут поддерживаться в будущем.

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

Шейдерное API

Общее

Каждый шейдер материала должен использовать предоставляемое API для единообразного согласования операций, это API находится в mtrl.h и предоставляет некоторые функции для решения частых задач при построении материалов.

Частное

Частное API используют разные нетривиальные сущности:

  • Растительность, файл green.h (организацию расчетов смотреть в mtrlgreen_tree_base.vs для деревьев и кустов, в mtrlgreen_grass_base.vs для травы);
  • Анимационные модели, файл skin.h (организацию расчетов смотреть в mtrlskin_base.vs).

Частное API выделено в отдельные компоненты шейдерной системы с целью единообразной обработки сущностей.

Константы

Общие

Пересылаемые в шейдер константы заранее известны и переопределены, их имена строго фиксированы и не подлежат изменениям, так как пересылка из движка в шейдер осуществляется по имени констант.

Самое главное чтобы их пересылка из движка и использование в шейдере было согласовано, иными словами движок должен отправлять константу, а шейдер должен принимать и использовать. Если движок будет пытаться переслать данные, которые не объявлены (не используются) то графическое ядро будет выдавать предупреждения, а если шейдер будет использовать неинициализированные данные, то результат непредсказуем.

Список возможных данных аналогичен списку в редакторе материалов. Имена данных:

  • g_mW - матрица мира;
  • g_mV - матрица вида;
  • g_mP - матрица проекции;
  • g_mWV - комбинированная матрица мира и вида;
  • g_mWVP - комбинированная матрица мира, вида и проекции;
  • g_vPosCam - float3 позиция камеры;
  • g_vTimeDelta - float2 вектор, x – общее время рендера в миллисекундах, y – текущее время рендера кадра в миллисекундах;
  • g_vWinSize - float4 вектор размеров окна рендера в пикселях, x – ширина, y - высота, z - размер одного пикселя по ширине (1 / ширина), w - размер одного пикселя по высоте (1 / высота).

Во всех случаях g_mW (трансформация нормали) и g_mWVP (трансформация позиции) являются обязательными для вершинного шейдера.

Список обязательных (пересылаемых по умолчанию) констант для пиксельного шейдера:

  • gvNearFarLayers - float4 вектор, x - ближняя плоскость отсечения, y - дальняя плоскость отсечения, z - тип поверхности (MTLTYPE_LAYER), w - идентификатор поверхности.

Константы растительности

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

Константы по регистрам:

  • GREEN_R_LESSENING регистр, константа half2 g_vDistLessening - дистанции начала и окончания уменьшения растительности (для травы);
  • GREEN_R_VIEWPOS регистр, константа half3 g_vViewPos - позиция наблюдателя;
  • GREEN_R_BSPHERE регистр, константа half4 g_vBoundSphere - сфера, xyz - центр, w - радиус;
  • GREEN_R_BBMAX регистр, константа half3 g_vBoundMax - максимум ограничивающего объема объекта;
  • GREEN_R_BBMIN регистр, константа half3 g_vBoundMin - минимум ограничивающего объема объекта.

Перечисленные константы необходимо объявлять непосредственно в вершинном шейдере растительности (травы или листвы деревьев/кустов) так:

half2 g_vDistLessening  : register(GREEN_R_LESSENING);
half3 g_vViewPos : register(GREEN_R_VIEWPOS);
half4 g_vBoundSphere : register(GREEN_R_BSPHERE);
half3 g_vBoundMax : register(GREEN_R_BBMAX);
half3 g_vBoundMin : register(GREEN_R_BBMIN);

Константы анимационных моделей

Вершинный шейдер анимационной модели принимает массив данных в одной константе по регистру ANIM_R_DATA (gdefines.h):

half4 g_BufferBoneWorld[128] : register(ANIM_R_DATA);

На каждую кость идёт две компоненты, смещение и вращение(кватернион), то есть, 128 регистров - 64 кости.

Объявления данная константа не требует, так как объявлена в подключаемом файле skin.h, которые долже быть подключен в каждый вершинный шейдер анимационной модели.

Сэмплеры

Все семплеры распределены по регистрам и именование большинства из них не является обязательным правилом, однако должно иметь приоритет. Список текстур по регистрам:

  • 0 - g_sColor, цвет, albedo текстура;
  • 1 - g_sMask, маска;
  • 2 - g_sDetails0, детальная текстура r канала;
  • 3 - g_sDetails1, детальная текстура g канала;
  • 4 - g_sDetails2, детальная текстура b канала;
  • 5 - g_sDetails3, детальная текстура a канала;
  • 6 - g_sNormals0, микрорельефная текстура r канала;
  • 7 - g_sNormals1, микрорельефная текстура g канала;
  • 8 - g_sNormals2, микрорельефная текстура b канала;
  • 9 - g_sNormals3, микрорельефная текстура a канала;
  • 10 - g_sParameters, параметры освещения поверхности;
  • 12 - g_sReflection, отражения, может быть 2d или cube;
  • 13 - g_sDepth, глубина, использовать только для полупрозрачных материалов.

Общая структура шейдеров

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

Для примера будет приведен базовый шейдер геометрии.

В качестве разделителя используется:

//##########################################################################

Первым элементом файла шейдера является его описание, которое до и после отделено новыми строками. Здесь необходимо привести название файла и краткое описание. Пример:

/*
mtrlgeom_base.vs
Базовый рендер геометрии
*/

Далее следуют подключаемые файлы:

#include <../struct.h>

Затем разделитель и принимаемые из движка константы (сюда же можно отнести статические данные и дефайны для данного шейдера):

half4x4 g_mWVP;
half4x4 g_mW;

Далее разделитель и сэмплеры:

sampler2D g_sColor:register(s0);
sampler2D g_sNormals0:register(s6);
sampler2D g_sParameters:register(s10);

Затем разделитель и main функция шейдера:

VSO_SceneCommon main(VSI_Geometry IN)
{
VSO_SceneCommon OUT;

OUT.vPosition = mul(half4(IN.vPosition,1.f),g_mWVP);
OUT.vNormal = mul(IN.vNormal,g_mW);
OUT.vTexUV = IN.vTexUV;
OUT.vPos = OUT.vPosition;

return OUT;
}

Если необходимы дополнительные функции то они должны находиться до main функции и отделяться сверху и снизу разделителями.

Функция main

Данный раздел содержит информацию о необходимых элементах функции main компилируемых шейдеров.

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

Так как разные абстрактные сущности геометрии игрового мира могут быть представлены различными структурами вершин (struct.h) (например простая сущность, вода и т.д.), то в первую очередь необходимо объявление объекта структуры (приведен пример общей структуры):

VSO_SceneCommon OUT;

Затем трансформация вершины WVP матрицей и трансформация нормали W матрицей:

OUT.vPosition = mul(half4(IN.vPosition, 1.f), g_mWVP);
OUT.vNormal = mul(IN.vNormal, g_mW);

И заполнение текстурных координат и трансформированной WVP позиции:

OUT.vTexUV = IN.vTexUV;
OUT.vPos = OUT.vPosition;

В конце функции необходим возврат объекта структуры:

return(OUT);

Пиксельный шейдер

В первую очередь необходимо отсечение пикселей по глубине:

ClipFar(IN.vPos.z, g_vNearFarLayers.y);

Затем нормализация нормали:

IN.vNormal = normalize(IN.vNormal);

После этого возможна реализация возможностей материала.

Все шейдеры материалов должны возвращать единообразный результат в виде структуры PSO_Gbuffer из struct.h Крайне не рекомендуется заполнять данные этой структуры вручную, для ее заполнения есть специальная API функция CreateGbuffer из mtrl.h, комментарии и описание внутри файла. Пример использования (mtrlgeom_base.ps):

return(CreateGbuffer(tex2D(g_sColor, IN.vTexUV), IN.vNormal, tex2D(g_sParameters,IN.vTexUV), IN.vPos, g_vNearFarLayers));