Texture blit: шейдеры обработки текстур
Источники, координаты цели, четыре выхода и формулы смешивания RGBA.
texture_blit задаёт одну GPU-операцию над DrawableTexture2D. Единственная функция blit() выполняется для пикселей прямоугольника назначения. Это не canvas_item-эффект, который автоматически выполняется при каждом отображении текстуры.
Полный шейдер копирования с окраской
Создайте ShaderMaterial с этим Shader и передайте его последним аргументом BlitRect. Перед записью инициализируйте цель через Setup; полный C#-помощник есть в руководстве DrawableTexture2D.
shader_type texture_blit;
uniform sampler2D source : hint_blit_source0;
uniform vec4 tint : source_color = vec4(1.0);
void blit() {
COLOR0 = texture(source, UV) * MODULATE * tint;
}Вызов target.BlitRect(rect, source, Colors.White, 0, material) берёт всю source и масштабирует в rect цели. Для всего результата используйте rect с размером цели. Uniform tint меняется на ShaderMaterial, но новое значение начнёт действовать только при следующем blit.
Режимы смешивания
S — выход шейдера, D — прежнее значение назначения, a — S.a. Для проверенного обычного RGBA8-пути действуют следующие правила до ограничения форматом:
| Режим | RGB | Alpha |
|---|---|---|
| blend_disabled | S.rgb | S.a |
| blend_mix | S.rgb × a + D.rgb × (1−a) | a + D.a × (1−a) |
| blend_add | S.rgb + D.rgb | S.a + D.a |
| blend_sub | D.rgb − S.rgb | D.a − S.a |
| blend_mul | S.rgb × D.rgb | S.a × D.a |
| blend_premul_alpha | S.rgb + D.rgb × (1−a) | a + D.a × (1−a) |
Собственный шейдер без render_mode использует blend_disabled. Материал по умолчанию у DrawableTexture2D явно задаёт blend_mix. Не переносите предположение о режиме одного в другой. В add/sub RGB здесь не умножается на alpha; таблица не обещает такую же арифметику CanvasItem или всех цветовых форматов.
Premultiplied alpha поддерживается шейдером. Для прямого, ещё не умноженного RGBA используйте полный пример ниже. Если вход уже premultiplied, второе умножение RGB нужно убрать.
shader_type texture_blit;
render_mode blend_premul_alpha;
uniform sampler2D source : hint_blit_source0;
void blit() {
COLOR0 = texture(source, UV) * MODULATE;
COLOR0.rgb *= COLOR0.a;
}Для этого режима используйте ShaderMaterial. У BlitMaterial данной версии объявленное PremultipliedAlpha выходит за пределы текущего кэша; этот путь не проверяется исполнением и не рекомендуется к вызову. Остальные пять режимов оболочки и сам shader blend_premul_alpha — разные пути.
Четыре источника и четыре выхода
Источник задаётся sampler2D с hint_blit_source0…hint_blit_source3. Переданные источники выбираются по порядку, не по имени переменной. MODULATE содержит цвет аргумента операции, но применить его должен код: COLOR0 не умножается на него автоматически.
Полный пример с двумя источниками и четырьмя выходами:
shader_type texture_blit;
uniform sampler2D source0 : hint_blit_source0;
uniform sampler2D source1 : hint_blit_source1;
uniform vec2 target_size = vec2(64.0, 32.0);
void blit() {
COLOR0 = texture(source0, UV) * MODULATE;
COLOR1 = texture(source1, UV) * MODULATE;
COLOR2 = vec4(UV, 0.0, 1.0);
COLOR3 = vec4(FRAGCOORD.xy / target_size, 0.0, 1.0);
}Используйте DrawableOps.Split из связанного руководства. Он передаёт источники first/second и три дополнительные цели. target_size должен совпадать с реальным базовым размером цели для этой диагностической записи FRAGCOORD. Пример по умолчанию рассчитан на 64×32.
COLOR0 соответствует основной цели, COLOR1…3 — дополнительным. Неиспользуемые выходы без назначенной цели отбрасываются. Но назначенный выход, которому код не присвоил значение, в текущем RD получает непрозрачный чёрный (0,0,0,1), а не прозрачный цвет. Не оставляйте такой выход в надежде сохранить прежние пиксели; при blend_disabled он их перезапишет.
Координаты и встроенные значения
UV проходит от 0 до 1 по записываемому прямоугольнику и позволяет выбрать весь источник. FRAGCOORD.xy — центр пикселя целевой текстуры текущего mipmap-уровня, а не окна или viewport. У частичного rect размером 32×16 в цели 64×32 UV и FRAGCOORD/размер цели различаются.
| Тип и имя | Значение |
|---|---|
in float TIME | Время рендерера в момент операции; не запускает повторный blit. Учитывает Engine.TimeScale, пауза дерева его не останавливает. Сброс rendering/limits/time/time_rollover_secs, обычно 3600 секунд. |
in float PI / TAU / E | Математические константы. |
in vec4 FRAGCOORD | Центр пикселя назначения; xy в пикселях целевого уровня. |
in vec2 UV | Нормализованные координаты записываемого прямоугольника. |
in vec4 MODULATE | Переданный операции цвет; это множитель, не маска записи каналов. |
out vec4 COLOR0 / COLOR1 / COLOR2 / COLOR3 | RGBA соответствующей цели. В текущем RD начальное значение каждого — (0,0,0,1). |
in — чтение, out — результат. У этого типа нет vertex(), fragment(), TEXTURE или COLOR из CanvasItem: источники и выходы объявляются по контракту texture_blit. TIME и константы доступны глобально, остальные имена — в blit().
Ограничения и диагностика
1–4 цели должны быть одного размера; запрошенный mipmap обязан существовать. Источники не могут совпадать с целями. AtlasTexture не поддерживается ресурсным BlitRect как вырезка; берите исходный атлас и считайте UV самостоятельно. Изменение uniform, источника или времени без новой операции не обновляет записанные пиксели. Для цепочки эффектов используйте чередование двух ресурсов.
| Симптом | Что проверить |
|---|---|
| Материал не даёт нужного эффекта | shader_type texture_blit и передача material именно в текущий вызов blit. |
| Alpha записалась вместо смешивания | render_mode собственного шейдера; по умолчанию blend_disabled. |
| Цвет слишком тёмный с premultiplied alpha | RGB мог быть умножен на alpha дважды. |
| Дополнительная цель стала чёрной | Явную запись нужного COLOR1/2/3. |
| Координаты смещены | Различие UV прямоугольника и FRAGCOORD цели, особенно на mipmap. |
| Отдельный канал не сохранился | MODULATE не является маской каналов; нужна явная формула и отдельный источник прежнего значения. |
Проверены три полных шейдера, все приведённые режимы смешивания в обычном RGBA8, выходы и координаты на Windows Forward+/Vulkan. Настройки цветов других форматов, вся матрица рендереров/платформ и производительность не имеют здесь полной runtime-проверки. Ограничение кэша BlitMaterial выявлено по исходникам, опасный enum не запускается; ядро движка для этой документации не менялось.