Розробка шейдерів для мобільної гри
Мобільний GPU—це не десктопний GPU з зниженими частотами. Архітектура tile-based deferred rendering (TBDR) на Apple GPU (PowerVR-спадщина) та Arm Mali принципово відрізняється від immediate mode rendering на десктопних Nvidia/AMD. Шейдер, написаний без розуміння цієї різниці, на мобілі працює в 3–5 разів повільніше, ніж міг би.
Архітектурні обмеження, які змінюють підхід до шейдерів
Fillrate та overdraw. Мобільні GPU чутливі до overdraw—коли один піксель растеризується кілька разів. Кожен додатковий draw call поверх вже нарисованого коштує дорого. Для Unity: Sorting Layer + правильна Queue у шейдері (Geometry перед Transparent) дозволяють рендерові використовувати early-z rejection. Прозорі об'єкти вбивають early-z—мінімізуйте їхню кількість.
Точність. На мобілі різниця між float (32 біти), half (16 бітів) та fixed (10 бітів, застаріло) помітна. Arm Mali та Adreno підтримують нативну 16-бітну арифметику, і на них half працює вдвічі швидше, ніж float. Позиції вершин—float, кольори та UV—half. У GLSL ES 3.0 це highp vs mediump.
Семплування текстур. Mip-mapping обов'язковий. Без нього texture sampler'и працюють з повною розділением навіть для дрібних об'єктів на екрані—це bandwidth-убійця на мобільних з розділеною пам'яттю CPU/GPU.
Шейдери в Unity: URP vs Built-in
Universal Render Pipeline—стандарт для мобільних Unity-ігр. Shader Graph дозволяє будувати шейдери візуально, але вузькі місця все одно потребують HLSL-редакцій. Кастомний SubGraph у Shader Graph—переиспользуємий блок, який компілюється один раз.
Приклад простого шейдера розчинення (dissolve) на URP HLSL:
half4 frag(Varyings input) : SV_Target {
half4 baseColor = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv);
half noiseValue = SAMPLE_TEXTURE2D(_NoiseMap, sampler_NoiseMap, input.uv).r;
// cutout за порогом з м'якою границею
half edge = smoothstep(_Threshold - _EdgeWidth, _Threshold + _EdgeWidth, noiseValue);
clip(noiseValue - _Threshold); // відкидаємо пікселі
half3 edgeColor = lerp(baseColor.rgb, _EdgeColor.rgb, edge);
return half4(edgeColor, baseColor.a);
}
clip() на мобілі працює швидко—TBDR архітектура відкидає тайл ще до растеризації, якщо всі пікселі обрізані.
Постефекти: що допустимо на мобілі
Повноекранні постефекти (bloom, depth of field, motion blur)—дорого. Стратегія:
-
Bloom—через
Kawase blurзамість Gaussian. Kawase робить менше семплів при порівняній якості. У URPBloomoverride зHigh Quality Filtering = offдля мобільного пресету. -
Колірна корекція—
Tonemapping+Color Adjustmentsмайже безплатно, виконується в одному проході. - DOF—тільки для кінематичних сцен, не в геймплеї. Bokeh DOF на мобілі—приблизно 3 мс додатково на Snapdragon 778G.
-
Motion blur—краще імітувати через
Trail Rendererна конкретних об'єктах, ніж повноекранний velocity buffer.
Particle-шейдери та VFX
VFX Graph потребує Compute Shader—підтримується на Vulkan (Android 7+) та Metal (iOS 11+). Старий Particle System працює через CPU, гірше з багатьма частинками. Для мобільного: VFX Graph на сучасних пристроях, CPU particles як fallback для бюджетних телефонів.
Particle-шейдери повинні бути максимально простими: Unlit, Additive blending, half precision, без Lighting. Lit-шейдер на 500 частинках—поширена помилка, яка дає –10 FPS.
Godot та GLSL ES
У Godot 4, шейдери пишуться на GLSL з власними розширеннями (uniform, varying замінені на uniform та out). Шейдерна мова Godot компілюється в SPIR-V (Vulkan) або GLSL ES (сумісність). Для мобільного експорту Godot використовує Compatibility renderer на основі OpenGL ES 3.0—ширша підтримка, ніж Vulkan на старих Android.
Оцінка робіт
Обсяг шейдерного коду сильно залежить від візуального стилю гри: стилізована 2D з cel-shading—1–2 кастомні шейдери, реалістична 3D з PBR, водою та атмосферою—10+. Тривалість: від 3 днів до 4–6 тижнів. Вартість розраховується індивідуально.







