Разработка кастомных шейдеров постобработки
Встроенные Volume эффекты в URP и HDRP — Bloom, Color Grading, Vignette — закрывают базовые потребности, но как только нужен нестандартный визуальный эффект (тепловое марево над асфальтом, хроматическая аберрация с кастомной кривой, pixel art posterization, outline detection по depth buffer) — начинается территория кастомных Renderer Feature и полноэкранных Blit Shader'ov. Мы решаем такие задачи, разрабатывая шейдеры под ключ для мобильных и ПК-платформ. За 5+ лет мы реализовали более 80 уникальных постэффектов — от простых цветокоррекций до составных многоэтапных pipeline. 90% эффектов проходят оптимизацию под мобильные GPU, что экономит до 30% FPS на Mali G72. Каждый эффект проходит этап прототипирования на целевой сцене с учётом FPS budget и платформенных ограничений. Свяжитесь с нами для обсуждения вашего визуального эффекта — мы подберём оптимальный подход и оценим трудозатраты.
ScriptableRendererFeature Documentation
Как работает ScriptableRendererFeature?
ScriptableRendererFeature регистрирует ScriptableRenderPass, который выполняется в заданном RenderPassEvent. Пошаговая инструкция:
- Создайте класс, наследуемый от
ScriptableRendererFeature. - В нём объявите
ScriptableRenderPassи настройте его материал, события. - В методе
AddRenderPassesдобавьте проход в очередь. - В кастомном
ScriptableRenderPass.ExecuteиспользуйтеBlitter.BlitCameraTexture(cmd, source, destination, material, passIndex)для применения шейдера. - Назначьте созданный Feature в URP Renderer через Inspector.
Материал для Blit лучше всего создавать через Full Screen Shader Graph (тип графа Fullscreen Shader в URP). В этом графе доступен URP Sample Buffer — нода, которая читает Color, Depth, Normal или Motion Vectors из внутренних буферов. Без этой ноды нельзя сделать глубиноориентированные эффекты (outline по depth, кастомный DOF) через ShaderGraph — придётся писать HLSL в Custom Function.
Как реализовать Outline по Depth и Normal?
Outline detection — частый запрос для стилизованных игр. Наивный подход с обводкой через второй проход вершин работает для простых объектов, но ломается на сложной геометрии и не даёт силуэтного edge detection.
Правильный подход — полноэкранный edge detection через Depth и Normal buffers. Depth-based edge: читаем глубину в текущем пикселе и соседях (4 или 8 через Sample Texture 2D с offset). Если разница глубины превышает порог — пиксель на краю. Roberts Cross или Sobel — стандартные фильтры.
Normal-based edge: аналогично по Normal buffer. Даёт линии на перепадах нормалей — рёбра и складки, которые depth не видит. Комбинация depth + normal — стандарт для cel-shading outline.
Почему важно линеаризовать Depth?
Глубина в буфере нелинейна (logarithmic или reversed-Z в зависимости от платформы). Прямое сравнение depth значений даёт неравномерную толщину линии. Необходимо линеаризовать через LinearEyeDepth(depth, _ZBufferParams) — в ShaderGraph это нода Linear Eye Depth. Без этого outline будет тоньше на переднем плане и толще на дальнем.
Сроки разработки постэффектов
| Тип постэффекта | Срок |
|---|---|
| Простой fullscreen эффект (цветокоррекция, blur) | 1–3 дня |
| Outline по depth/normal + настройка | 3–5 дней |
| Distortion эффект (heatwave, portal) | 3–6 дней |
| Сложный составной эффект (несколько passes) | 1–2 недели |
Сравнение подходов: Shader Graph vs Custom HLSL
| Критерий | Full Screen Shader Graph | Custom HLSL |
|---|---|---|
| Скорость разработки | Высокая (визуальное редактирование) | Низкая (ручное написание кода) |
| Гибкость | Ограничена доступными нодами | Полная, любой эффект |
| Производительность | Средняя (автоматические оптимизации) | Высокая (ручная оптимизация) |
| Кроссплатформенность | Автоматическая | Требует платформенных #define |
Как добиться качественного distortion?
Screen-space distortion (heatwave, magic portal) — Blit-шейдер, смещающий UV текущего кадра по Normal map. Проблема: distortion должен работать с Opaque Texture (_CameraOpaqueTexture), чтобы не захватывать прозрачные и UI элементы. Если эффект нужен только над определённым объектом — потребуется отдельный Distortion Renderer Feature, который рендерит маску в промежуточный RT.
В HDRP distortion реализован проще: встроенный Distortion render queue, объекты с Distortion enabled автоматически попадают в distortion pass.
Как избежать типичных ошибок?
Неверный RenderPassEvent. Если поставить постэффект в BeforeRenderingPostProcessing, тогда Bloom будет поверх кастомного эффекта. Порядок событий: Opaques → Skybox → Transparents → Post Processing → UI. Выбор RenderPassEvent определяет место в этой очереди.
Отсутствие Depth Priming Mode. На мобильных GPU (Mali) глубинный буфер может быть недоступен в кастомном pass, если Depth Priming Mode в URP Renderer не принудительно включён. Результат — чёрный экран или некорректные значения depth без ошибок в консоли.
VR incompatibility. Кастомный шейдер без поддержки XR ломается в VR — двойное изображение или только один глаз. Blitter.BlitCameraTexture автоматически обрабатывает VR single-pass, но кастомные UV-расчёты в нодах требуют UNITY_STEREO_EYE_INDEX_POST_VERTEX. Все наши шейдеры учитывают это, поэтому работают корректно на любых VR-шлемах.
Что включает разработка кастомного постэффекта?
При заказе кастомного постэффекта мы проводим анализ требований, прототипируем эффект на вашей сцене, интегрируем его в render pipeline с учётом целевых платформ (мобильные, PC, консоли, VR) и оптимизируем под FPS budget и fillrate. В итоге вы получаете исходный код шейдера, настроенный RendererFeature, пример сцены, документацию и 2 месяца поддержки после внедрения. Стоимость зависит от сложности и объёма работ — мы оцениваем её индивидуально после анализа. Закажите разработку — получите консультацию по вашему визуальному эффекту.






