Розроблення шейдерів постобробки для ігор
Фінальний кадр у ігровому рендері — це не те, що виходить з геометричного pipeline. Між G-Buffer та екраном стоїть стек постобробки, і саме він визначає, чи має зображення характер чи ні. Bloom з невірним threshold розмиває highlights у білу кашу. Chromatic aberration з фіксованим offset виглядає як артефакт, а не стилізація. Самописний шейдер depth of field, який не враховує CoC (circle of confusion) коректно, дає характерну "замуленість" на межах переднього плану.
Це не абстрактні проблеми — це те, що відрізняє проект з нормальним візуальним стеком від проекту, де "щось не так, але невідомо що".
Де ломається стандартний стек постобробки
Unity URP/HDRP та Unreal Engine обидва надають Volume Framework для постобробки — але у кожного є зони, де стандартні ефекти не покривають потреби конкретного візуального стилю.
У URP найчастіша біль — відсутність нативної підтримки кастомних passes у 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, який виглядає як баг рендерера, але причина у шейдері.
Що реально робиться у рамках цієї послуги
Розроблення постпроцесингового шейдера — це не "написати HLSL". Це цикл з кількох етапів, у кожного є свої інструменти.
Аналіз візуального референсу та постановка задачі. До написання першого рядка коду — зрозуміти, що саме потрібно відтворити. Cel-shading з edge detection через Sobel на глибині та нормалях відрізняється від cel-shading через Step у освітленні. Це різні шейдери з різними trade-off по продуктивності.
Прототипування в Shader Graph / Material Editor. ShaderGraph у Unity дозволяє швидко перевірити гіпотезу без ручної компіляції. Для Unreal — Material Graph. Прототип робиться за 1–2 дні, після чого приймається рішення: залишити в нодовій системі або переписати в HLSL/Custom HLSL node для оптимізації.
Написання та оптимізація HLSL/GLSL. Фінальний шейдер пишеться з урахуванням платформи. Мобільний таргет — це mediump float, мінімум текстурних samples, відсутність discard. PC/консоль — можна дозволити fullscreen pass з кількома Blit та compute-шейдером для separation pass у Gaussian blur.
Інтеграція в pipeline. ScriptableRenderPass для URP, CustomPassVolume для HDRP, Post Process Material для Unreal. Включаючи налаштування Injection Point, порядку виконання та сумісності з Motion Vectors якщо потрібен TAA.
Профілювання. RenderDoc для frame capture, Unity Frame Debugger / Unreal RenderDoc plugin для аналізу passes. GPU Profiler для вимірювання часу конкретного pass. На мобільних — Snapdragon Profiler або Mali Graphics Debugger.
На одному з проектів — мобільна RPG у URP — замовник хотів кастомний ефект "чорнильного контуру" поверх геометрії. Перший прототип через ScriptableRenderPass з Roberts Cross на depth давав 4ms на Adreno 650 при 1080p. Після переписки на single-pass з упрощеним ядром та використанням _CameraDepthNormalsTexture замість двох окремих текстур — 1.1ms. Різниця не в алгоритмі, а в кількості текстурних fetches.
Етапи роботи над шейдером
| Етап | Що робиться | Приблизні терміни |
|---|---|---|
| Розбір референсу та ТЗ | Аналіз візуального стилю, визначення алгоритму | 1–2 дні |
| Прототип у ShaderGraph / Material Graph | Швидка перевірка гіпотези, узгодження | 1–3 дні |
| HLSL-реалізація | Написання шейдера під цільову платформу | 2–7 днів |
| Інтеграція у render-pipeline | ScriptableRenderPass / CustomPassVolume / PP Material | 1–3 дні |
| Профілювання та оптимізація | Frame capture, GPU timing, оптимізація під таргет | 1–4 дні |
| Документація та передача | Коментарі у коді, інструкція по налаштуванню | 0.5–1 день |
Складні ефекти з кількома passes (наприклад, volumetric fog через ray marching у постпроцесі або screen-space subsurface scattering) можуть займати 3–4 тижні з урахуванням ітерацій.
Типові помилки при самостійній розробці
Більшість проблем — не в алгоритмі, а в інтеграції.
Невірний RenderPassEvent. Вставка кастомного pass у BeforeRenderingPostProcessing без розуміння того, що URP на цьому етапі ще не застосував Color Grading — в результаті LUT накладається поверх кастомного ефекту, а не під ним.
Ігнорування camera stacking. У URP при Overlay Camera кастомний ScriptableRenderPass, підключений до Base Camera, не виконується для Overlay — потрібно реєструвати pass в обох Renderer Asset або використовувати Universal Renderer з правильним флагом renderingLayerMask.
Hardcode розширення. float2(1.0/1920.0, 1.0/1080.0) у шейдері замість _ScreenParams.zw - 1 — на пристроях з нестандартним розширенням або при dynamic resolution ефект ломається.
Втрата HDR. Якщо ефект застосовується після tonemap, а розраховується для лінійного HDR-буфера — кольори будуть некоректні. Важливо явно визначити точку застосування у pipeline.
Вартість розраховується після аналізу технічного завдання: платформа, цільовий render-pipeline, складність алгоритму та вимоги до продуктивності.





