Розробка кастомних шейдерів постобробки
Вбудовані Volume ефекти в URP та HDRP — Bloom, Color Grading, Vignette — закривають базові потреби, але як тільки потрібен нестандартний візуальний ефект (теплове марево над асфальтом, хроматична аберація з кастомною кривою, pixel art posterization, outline detection по depth buffer) — починається територія кастомних Renderer Feature та повноекранних Blit Shader'ів. Ми вирішуємо такі задачі, розробляючи шейдери під ключ для мобільних та ПК-платформ. За 5+ років ми реалізували понад 80 унікальних пост-ефектів — від простих кольорокорекцій до складних багатоетапних pipeline. 90% ефектів проходять оптимізацію під мобільні GPU, що економить до 30% FPS на Mali G72. Кожен ефект проходить етап прототипування на цільовій сцені з урахуванням FPS budget та платформених обмежень. Зв'яжіться з нами для обговорення вашого візуального ефекту — ми підберемо оптимальний підхід та оцінимо трудозатрати.
Документація ScriptableRendererFeature
Як працює 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 місяці підтримки після впровадження. Вартість залежить від складності та обсягу робіт — ми оцінюємо її індивідуально після аналізу. Замовте розробку — отримайте консультацію щодо вашого візуального ефекту.






