Перенос GLSL: этапы, координаты и входы эффекта
Полный fragment-пример, явные uniforms и проверка координат без слепых замен.
При переносе согласуйте входы, системы координат и выходы шейдера, а не только имя точки входа. Обычный Shader Reckfell использует язык шейдеров движка; исходный GLSL compute через RenderingDevice — другой способ работы.
Определите, что рисует шейдер
Для материала CanvasItem в 2D используйте canvas_item, для поверхности 3D — spatial, для частиц, неба или тумана — соответствующий специальный тип. Пример ниже — эффект ColorRect в 2D. Он не превращает произвольную пару vertex/fragment в материал 3D и не заменяет многопроходный рендеринг.
В обычном шейдере движка нет GLSL #version, межэтапного интерфейса layout(location=...) и точки входа main. Задайте shader_type и используйте vertex(), fragment() и другие функции выбранного типа. Общие вспомогательные функции могут остаться обычными функциями с поддерживаемыми типами параметров.
Полный пример переноса fragment
Сохраните исходник как PortedUv.reckfellshader:
shader_type canvas_item;
render_mode unshaded;
uniform vec2 effect_resolution = vec2(128.0, 128.0);
uniform float effect_time = 0.0;
void mainImage(out vec4 frag_color, vec2 frag_coord) {
vec2 size = max(effect_resolution, vec2(1.0));
vec2 position = frag_coord / size;
frag_color = vec4(position, 0.25 + 0.25 * sin(effect_time), 1.0);
}
void fragment() {
vec4 result;
vec2 size = max(effect_resolution, vec2(1.0));
mainImage(result, UV * size);
COLOR = result;
}Загрузите его через ResourceLoader.Load<Shader>("asset://PortedUv.reckfellshader"), назначьте в ShaderMaterial.Shader, затем назначьте материал видимому ColorRect. Проверенная карточка имеет размер 128×128. Красный канал растёт слева направо, зелёный — сверху вниз; синий при effect_time=0 примерно равен 0.25.
Для изменения времени вызовите material.SetShaderParameter("effect_time", Mathf.Pi / 2). Синий поднимется примерно до 0.5 без замены ресурса Shader. Это явный вход времени: вызывающий код определяет влияние паузы, масштаба времени или повтора. Помощник mainImage сохраняет интерфейс выходного цвета и координаты; fragment передаёт координаты и записывает COLOR.
Пользовательский uniform effect_resolution описывает выбранную область координат эффекта. Он не получает автоматически размер viewport, элемента или текстуры. В примере нормализованного градиента UV умножается на размер этой области перед обратным делением внутри функции, поэтому изменение области сохраняет градиент. Для эффектов с учётом пропорций задайте свою нормализацию вместо механической таблицы замен.
Сопоставляйте каждый интерфейс отдельно
| Понятие исходника | Решение в движке |
|---|---|
| main / mainImage | Перенесите работу этапа в fragment/vertex либо вызовите помощник из функции этапа. Согласуйте направления параметров и запись выхода. |
| gl_FragColor | COLOR в canvas_item fragment. Пространственная поверхность обычно записывает ALBEDO и другие выходы материала. |
| gl_Position | Выход в clip space GLSL, а не прямое переименование в VERTEX. Обычный VERTEX зависит от этапа/типа и преобразуется движком. |
| Атрибуты вершин / varyings | Используйте поддерживаемые встроенные значения и объявленные varying; не копируйте layout locations вслепую. |
| gl_FragCoord | FRAGCOORD для работы с пикселями viewport на подходящем этапе. Это не та же область, что UV отдельного элемента. |
| Размеры текстуры | TEXTURE_PIXEL_SIZE для встроенной текстуры canvas либо textureSize конкретного sampler. |
| Размеры viewport | SCREEN_PIXEL_SIZE в canvas fragment даёт обратные размеры viewport, а не локальный размер спрайта. |
| Внешние каналы текстур | Объявите sampler uniforms и назначьте нужные текстуры. Встроенная TEXTURE не заменяет автоматически каждый канал. |
| Внешние время, мышь, кадр, дата | Передайте явные uniforms, если важна исходная семантика. TIME не гарантирует чужое поведение паузы или сброса. |
| Макросы и include | Следуйте препроцессору движка; у обычного шейдера и raw GLSL compute разные пути обработки исходника. |
Проверьте координаты и цвет до полного эффекта
Начните с градиента координат или четырёх разных цветов углов. У проверенного ColorRect UV растёт вправо и вниз. Универсальное отражение Y добавлять нельзя: исходные соглашения, текстуры, поверхности и пути рендеринга могут различаться. Если эффект отражён, найдите конкретный изменивший ориентацию вход и исправьте его на границе один раз.
Разделяйте выборку текстуры, модуляцию CanvasItem, смешивание альфа и преобразование цветового пространства. Входной COLOR canvas fragment уже может учитывать текстуру/модуляцию; повторное считывание и умножение той же текстуры способно затемнить результат. Подсказки source_color для sampler/uniform описывают цветовые данные; нормали, маски и числовые буферы требуют своего представления. Градиент выше не использует текстуру и не проверяет все случаи выборки и прозрачности.
Переносите по этапам
- Скомпилируйте постоянный цвет для правильного типа шейдера.
- Подтвердите градиент координат и размеры эффекта.
- Добавляйте по одной текстуре/входу и явно задавайте uniforms.
- Верните алгоритм, затем отдельно проверьте альфа, цвет и движение.
- Воссоздайте многопроходное поведение через подходящие viewport или интеграцию рендеринга: копирование fragment-функции не создаёт буферы прошлого кадра или обратную связь.
Если шейдер компилируется, но выглядит неверно, проверьте размеры и ориентацию входов до изменения алгоритма. При ошибке компиляции сначала разберите первую ошибку этапа/типа/синтаксиса, затем зависимые сообщения. Одно переименование функции не является проверенным переносом.
В движке отрисован полный шейдер, проверены обе оси UV и выходной цвет, обновлены uniforms времени/размеров с сохранением идентичности Shader. Произвольные возможности GLSL, преобразования clip space 3D, сочетания текстурных каналов, обратная связь нескольких проходов и все рендереры/платформы не проверены этим примером.