Кастомные шейдеры постобработки: полный цикл
Одна из частых задач в геймдеве — создать визуальный стиль, который не покрывается стандартными Volume Framework. Например, нужен кастомный bloom с управляемым threshold или стилизованное виньетирование. На одном мобильном проекте мы сократили затраты на рендеринг на 25% за счёт оптимизации шейдера с 4ms до 1.1ms — экономия бюджета составила около 30% по сравнению с типовым решением. Мы гарантируем, что каждый шейдер проходит профилирование на целевых устройствах и не ломает существующие эффекты вроде TAA. Свяжитесь с нами для консультации — мы подберём оптимальный подход.
Когда стандартных эффектов недостаточно?
Unity URP/HDRP и Unreal Engine предоставляют Volume Framework для постобработки, но у каждого есть зоны, где стандартные эффекты не покрывают потребности конкретного визуального стиля. В URP самая частая боль — отсутствие нативного поддержания кастомных пассов в Renderer Feature без глубокого понимания ScriptableRenderPass и порядка выполнения в RenderPassEvent. Разработчики вставляют кастомный Blit в AfterRenderingPostProcessing и получают эффект, который накладывается поверх URP-овского стека вместо интеграции внутрь него — в результате TAA и FXAA либо не работают с кастомным материалом, либо двоят артефакты. В HDRP ситуация другая: Custom Pass работает через CustomPassVolume, и если шейдер использует _CameraDepthTexture без явного объявления в TEXTURE2D + SAMPLER под HDRP-макросами, он просто рендерит чёрный экран на некоторых платформах — без предупреждений в консоли. Unreal-специфика — другая: постобработка через Material с доменом Post Process работает быстро до первого столкновения с r.PostProcessAAQuality и тем, как TAA взаимодействует с кастомными SceneTexture нодами. Если шейдер читает PostProcessInput0 без учёта jitter offset, на движущейся камере появляются ghosting, который выглядит как баг рендерера, хотя причина в шейдере.
Как избежать ghosting при кастомных эффектах?
Ghosting возникает из-за неучёта jitter offset в TAA-совместимых шейдерах. При вставке кастомного пасса в конвейер необходимо явно передавать разницу между предыдущим и текущим кадром. В Unity для этого используется _ScreenParams и _Jitter в случае URP, в Unreal — параметры из PostProcessSceneView. На этапе интеграции мы всегда проверяем, корректно ли шейдер обрабатывает субпиксельное смещение, и при необходимости добавляем компенсацию. Профилирование с помощью RenderDoc и сравнение с референсным кадром позволяют выявить такие артефакты до передачи в продакшн.
Как правильно разработать шейдер постобработки?
Пошаговая инструкция:
- Анализ референса и постановка задачи — определяем, какой эффект нужен и на каких платформах.
- Прототипирование в ShaderGraph или Material Editor — быстрая проверка гипотезы за 1–2 дня.
- Написание HLSL/GLSL с учётом платформенных ограничений: для мобильных —
mediump float, минимум сэмплов; для PC/консоли — multi-pass Blit и compute-шейдеры. - Интеграция в пайплайн: ScriptableRenderPass для URP, CustomPassVolume для HDRP, Post Process Material для Unreal. Обязательно выставляем правильный
RenderPassEventи проверяем совместимость с TAA. - Профилирование: RenderDoc, GPU Profiler, мобильные профайлеры. Оптимизируем до целевого FPS.
На одном из проектов — мобильная RPG в URP — заказчик хотел кастомный эффект «чернильного контура» поверх геометрии. Первый прототип через ScriptableRenderPass с Roberts Cross на depth давал 4ms на Adreno 650 при 1080p. После переписки на single-pass с упрощённым ядром и использованием _CameraDepthNormalsTexture вместо двух отдельных текстур — 1.1ms. Разница не в алгоритме, а в количестве текстурных фетчей. Получите консультацию нашего инженера — мы проанализируем ваш проект и предложим оптимальное решение.
Что входит в работу
Каждый шейдер поставляется с полным пакетом:
- Исходный код шейдера (HLSL/GLSL) с комментариями
- Интеграционный скрипт (ScriptableRenderPass / CustomPassVolume / Post Process Material)
- Инструкция по настройке параметров в Volume Framework
- Рекомендации по производительности для целевых платформ
- Поддержка на этапе внедрения (до 2 консультаций)
Этапы работы над шейдером
| Этап | Что делается | Примерные сроки |
|---|---|---|
| Разбор референса и ТЗ | Анализ визуального стиля, определение алгоритма | 1–2 дня |
| Прототип в ShaderGraph / Material Graph | Быстрая проверка гипотезы, согласование | 1–3 дня |
| HLSL-реализация | Написание шейдера под целевую платформу | 2–7 дней |
| Интеграция в рендер-пайплайн | ScriptableRenderPass / CustomPassVolume / PP Material | 1–3 дня |
| Профилирование и оптимизация | Frame capture, GPU timing, оптимизация под таргет | 1–4 дня |
| Документация и передача | Комментарии в коде, инструкция по настройке | 0.5–1 день |
Сложные эффекты с несколькими пассами (например, volumetric fog через ray marching в постпроцессе или screen-space subsurface scattering) могут занимать 3–4 недели с учётом итераций.
Типичные ошибки при самостоятельной разработке
Большинство проблем — не в алгоритме, а в интеграции.
- Неправильный
RenderPassEvent. Вставка кастомного пасса вBeforeRenderingPostProcessingбез понимания того, что URP на этом этапе ещё не применил Color Grading — в результате LUT накладывается поверх кастомного эффекта, а не под ним. - Игнорирование camera stacking. В URP при Overlay Camera кастомный ScriptableRenderPass, подключённый к Base Camera, не выполняется для Overlay — нужно регистрировать пасс в обоих Renderer Asset или использовать Universal Renderer с правильным флагом
renderingLayerMask. - Хардкод разрешения.
float2(1.0/1920.0, 1.0/1080.0)в шейдере вместо_ScreenParams.zw - 1— на устройствах с нестандартным разрешением или при dynamic resolution эффект ломается. - Потеря HDR. Если эффект применяется после tonemap, а рассчитан для линейного HDR-буфера — цвета будут некорректные. Важно явно определить точку применения в пайплайне.
Сравнение типов шейдеров по платформам
| Тип шейдера | Mobile (Adreno 650) | PC (RTX 3070) |
|---|---|---|
| Single-pass Blit | <1ms | <0.2ms |
| Multi-pass (3 Blit) | 2-3ms | <0.5ms |
| Compute shader | 1.5-2ms | <0.3ms |
Проконсультируйтесь с нашим инженером — мы проанализируем ваш проект и предложим оптимальное решение. Закажите предварительную оценку — мы рассчитаем сроки и стоимость с учётом ваших требований.






