reckfellENGINE

Язык шейдеров: типы, этапы и области uniform

Полный пример, правила языка, данные material/global/instance и реальные ограничения.

На этой странице

Язык шейдеров движка описывает работу конкретного этапа рендеринга. Он похож на GLSL, но обычный Shader не является программой raw GLSL: выберите shader_type и функции этапов этого типа. Для чужого кода см. перенос GLSL, для вычислений raw GLSL — compute через RenderingDevice.

Начните с законченного примера

Следующий canvas_item показывает типизированные функции, перегрузки, массивы, структуру, циклы, матрицу, varying и три области uniform. Он рисует проверочный градиент; это не пример производительности или демонстрационная сцена.

До открытия шейдера в редакторе определите глобальный float rf_docs_gain со значением 1.0. В project.reckfell это запись rf_docs_gain={"type":"float","value":1.0} внутри секции [shader_globals]. После внешнего редактирования файла перезагрузите проект. Не регистрируйте повторно из кода имя, уже определённое проектом.

Для создания во время выполнения без такой настройки вызовите RenderingServer.GlobalShaderParameterAdd("rf_docs_gain", RenderingServer.GlobalShaderParameterType.Float, 1f) до загрузки шейдера. Проверены оба способа запуска. Имя и тип регистрации должны совпадать с объявлением шейдера.

Сохраните исходник как LanguageFeatures.reckfellshader, загрузите через ResourceLoader.Load<Shader>, назначьте в ShaderMaterial и примените материал к белому ColorRect размером 128×128:

Шейдер
shader_type canvas_item;
render_mode unshaded;

const float LEVELS[3] = float[3](0.125, 0.25, 0.5);

group_uniforms Surface;
uniform float gain : hint_range(0.0, 1.0) = 1.0;
uniform int palette : hint_enum("Base", "High") = 0;
uniform bool visible_effect = true;
group_uniforms;

global uniform float rf_docs_gain;
instance uniform float item_gain = 1.0;
varying vec2 local_uv;

struct SurfaceSample {
    vec3 rgb;
    float alpha;
};

float evaluate(float value) {
    return value * 0.5;
}

vec2 evaluate(vec2 value) {
    return value * 0.5;
}

void add_red(inout vec3 rgb) {
    rgb.r += 0.125;
}

SurfaceSample sample_surface(vec2 uv) {
    float samples[2] = float[2](LEVELS[0], LEVELS[1]);
    float total = 0.0;
    for (int i = 0; i < samples.length(); i++) {
        total += samples[i];
    }
    int step = 0;
    while (step < 2) {
        step++;
        if (step == 2) {
            break;
        }
        total += 0.125;
    }
    switch (palette) {
        case 0:
            break;
        case 1:
            total = LEVELS[2] + 0.25;
            break;
        default:
            total = LEVELS[0];
            break;
    }
    mat2 axes = mat2(vec2(0.0, 1.0), vec2(1.0, 0.0));
    SurfaceSample result;
    result.rgb = vec3(evaluate(axes * uv), evaluate(total));
    result.alpha = 1.0;
    return result;
}

void vertex() {
    local_uv = UV;
}

void fragment() {
    if (!visible_effect) {
        discard;
    }
    SurfaceSample result = sample_surface(local_uv);
    add_red(result.rgb);
    result.rgb *= gain * rf_docs_gain * item_gain;
    COLOR = vec4(result.rgb, result.alpha);
}

В пикселе (32, 32) проверенный результат примерно равен (0.252, 0.127, 0.25) до округления при хранении цвета. Матрица меняет местами оси UV: зелёный растёт вправо, красный — вниз. Palette 1 меняет синий примерно на 0.375. Две карточки могут использовать общий материал; переопределение item_gain меняет только выбранную карточку.

Типы, конструкторы и операции

ГруппаПрименение и ограничения
bool, bvec2/3/4Логические значения; для управления потоком используйте скалярное условие.
int / ivec2/3/4, uint / uvec2/3/4Знаковые/беззнаковые целые; используйте литерал вроде 1u, когда требуется uint.
float, vec2/3/4Числа с плавающей точкой и векторы. Квалификатор точности не запрашивает double из C#.
mat2/3/4Квадратные матрицы со столбцовым хранением. В примере столбцы заданы явно перед умножением вектора.
Семейства samplerСсылки на текстурные ресурсы, а не встроенные массивы пикселей. Согласуйте размерность и целочисленную/вещественную выборку с ресурсом.
voidВозврат функции без значения.

Если преобразование важно, задайте конструктор явно: float(index), vec3(value), vec4(rgb, alpha). Скалярный конструктор вектора заполняет компоненты; вектор не является коллекцией C#. Выбор перегрузки зависит от типов аргументов, а не только желаемого типа результата. Различайте целые и вещественные литералы: целочисленное деление не даёт дробной части.

Арифметика векторов покомпонентная; используйте dot/cross для соответствующих операций, а матричное умножение — для преобразования координат. Не переносите на матрицы специальные обратные операторы C# Transform2D. При совместимых типах доступны арифметика, сравнения, логические операции, целочисленные битовые операции/сдвиги, присваивания и условное выражение.

Swizzle выбирает и переставляет компоненты: xyzw для геометрии, rgba для цвета, stpq по смыслу. Не смешивайте семейства имён в одном swizzle и не присваивайте повторяющимся компонентам вроде xx. Нормализуйте направление только при необходимости; нулевой вектор не задаёт корректного направления для нормализации.

lowp/mediump/highp выбирают точность переменной. Доступность, фактическая точность и скорость зависят от backend/устройства; сохраняйте достаточную точность координат и проверяйте снижение на целевой платформе вместо обещания универсального ускорения.

Массивы, константы и структуры

Задавайте известный размер массива и инициализируйте все читаемые элементы. В примере есть глобальный константный и локальный инициализированный массив. .length() возвращает объявленную длину; допустимые индексы — от 0 до length−1. Динамический индекс тоже должен гарантированно оставаться в границах. Массив шейдера не является расширяемым List из .NET.

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

Объявляйте типы struct в глобальной области до использования, затем инициализируйте поля. Они объединяют значения и передаются/возвращаются функциями, как SurfaceSample. Объявление нового struct внутри другого struct отклоняется; uniform типа struct также отклоняется. Произвольный граф объектов C# этим не поддерживается.

Функции и управление потоком

Определяйте помощники перед вызывающими их функциями. Перегрузки могут различаться типами аргументов; рекурсия отклоняется. in — обычный вход, out передаёт результат, inout читает и меняет значение вызывающей стороны, const-вход запрещает изменение. Инициализируйте выходы на всех достижимых путях.

if/else, for, while, do/while и switch задают поток выполнения; break, continue и return меняют его. Осмысленно ограничивайте циклы. Один запуск шейдера не проходит последовательно по всему изображению, а соседние пиксели не являются обычными общими переменными.

discard завершает текущий fragment без записи его вклада в цвет/глубину. Это не запись чёрного и не универсальный ранний выход для любого этапа. Проверяйте связь со смешиванием и глубиной; ранее выполненная дорогая работа от discard не становится бесплатной.

Varying и встроенные значения

Varying передаёт данные между этапами: vertex примера записывает local_uv, fragment получает интерполяцию по примитиву. Это не uniform и не произвольная временная память для записи из любого помощника. smooth интерполирует, flat сохраняет значение примитива. Целочисленные vertex→fragment varying в этой реализации требуют flat.

Встроенные значения и разрешённые записи зависят и от shader_type, и от этапа. У UV, COLOR, VERTEX, TIME и FRAGCOORD нет одной универсальной системы координат или правила изменения. В частности, VERTEX не заменяет напрямую GLSL gl_Position. Перед копированием выражения сверяйтесь со справочником конкретного этапа.

Математические, векторные/матричные и текстурные функции относятся к языку шейдеров, не к API C#. Согласуйте перегрузки и sampler; производные, LOD текстур и операции с ограничением этапа требуют своих правил. Пример проверяет используемые операции, а не каждую встроенную функцию на всех рендерерах.

Выберите область uniform

ОбъявлениеВладелец значения и обновление
uniformЗначение принадлежит ShaderMaterial. SetShaderParameter меняет все объекты с этим общим материалом.
global uniformЗначение находится в глобальном реестре контекста рендеринга. До использования объявите/зарегистрируйте имя и тип; меняйте через GlobalShaderParameterSet.
instance uniformЗначение принадлежит рисуемому объекту. У CanvasItem используйте SetInstanceShaderParameter для изменения одного объекта без копирования материала.

В примере SetShaderParameter("gain", 0.5f) затемняет обе общие карточки, а item_gain=0.5f у правой — только правую. Nil в setter материала или CanvasItem восстанавливает соответствующее объявленное значение по умолчанию в проверенном случае. Имена чувствительны к регистру: сохранённый параметр с опечаткой ещё не доказывает, что шейдер его использует.

hint_range и hint_enum описывают элементы Inspector, а не проверку значений из кода. Программный gain=1.5 принимается даже при hint_range(0,1). Ограничивайте или отклоняйте значения, если алгоритму нужен предел. source_color задаёт цветовой вход для соответствующего преобразования пространства; не применяйте его вслепую к нормалям, маскам и числовым данным. Текстурные hints управляют подходящей выборкой, а не смыслом данных текстуры. group_uniforms организует метаданные Inspector без переименования самого uniform.

Текущие глобальные значения храните в состоянии приложения. В этой версии вызовы GlobalShaderParameterGet, GetList и GetType во время игры отклоняются реализациями рендеринга вне контекста редактора; не опрашивайте их в игровой логике. Global override приоритетнее базового значения: Set обновляет сохранённую основу при активном override, а SetOverride с Nil снимает переопределение и показывает обновлённую основу. Удаляйте глобальные параметры после прекращения использования зависимых материалов/шейдеров.

У per-instance здесь лимит выделения в 16 индексов; используйте простые скаляры/векторы и согласуйте явные instance_index, если материалы разделяют схему экземпляра. Матрицы и sampler в instance отклоняются. Сочетания массивов/материалов и многоповерхностные схемы требуют отдельной проверки. Общий объём uniform материала, выравнивание, количество sampler и varying также зависят от устройства/backend: учитывайте настоящее размещение вместо гарантии вместимости по названию платформы.

Если корректный шейдер выглядит неправильно

Сначала проверьте тип/этап шейдера, пространство координат, точное имя uniform, его область и значения по умолчанию. Затем отделите выборку/цветовое пространство, альфа/глубину и алгоритм. Разбирайте первую ошибку компилятора до зависимых сообщений. Компиляция, видимое поведение и скорость на целевой видеокарте — разные проверки.

В движке проверены полный шейдер и метаданные, обход hint_range, области material/global/instance, сброс override и discard на Windows Forward+/Vulkan. Неверные программы, все built-in/типы/точности/интерполяции, UI редактора и другие рендереры/экспорты требуют отдельной проверки. Более короткий прикладной пример — в правилах оформления.

Документация Reckfell EngineНаверх ↑
БЫСТРЫЙ ПЕРЕХОДНачало работыEntity и иерархияC# & .NET 10Сцены и префабы
Руководства и полный API Reckfell K
reckfellENGINE
RECKFELL ACCOUNT

Вход в аккаунт

Войдите в аккаунт Reckfell.

Один аккаунт для всей платформы Reckfell.