Мы разрабатываем системы частиц и VFX для мобильных игр, которые выглядят убедительно даже на бюджетных устройствах. В нашей практике десктопный эффект из 50 000 частиц на iPhone 11 приводил к перегреву и 20 FPS. Мы нашли предел: эффект выглядит качественно при 10 000 частицах или меньше, соблюдая температурный режим. С накопленным опытом более 5 лет мы подбираем оптимальный стек и технику для каждой платформы. Правильная система частиц повышает retention игроков на 15% по нашим данным, при этом не требует дорогих устройств.
Выбор инструмента: Unity vs SpriteKit vs Metal
Большинство мобильных игр используют одно из трёх: Unity Particle System (Shuriken), Apple SpriteKit SKEmitterNode, или кастомную систему на Metal/OpenGL ES/Vulkan для особых требований. Сравним их в таблице.
| Инструмент | Платформа | Производительность | Гибкость | Когда использовать |
|---|---|---|---|---|
| Unity Shuriken | Cross-platform | Высокая (GPU Instancing) | Средняя | 2D/3D игры на Unity |
| SpriteKit SKEmitterNode | iOS | Очень высокая (нативный) | Низкая | 2D игры только на iOS |
| Metal Compute Shaders | iOS | Максимальная | Высокая | Сложные кастомные эффекты |
Unity Shuriken — де-факто стандарт. Визуальный редактор, поддержка Sub Emitters, GPU Instancing, Burst компилятор для CPU-симуляции. VFX Graph (GPU-симуляция через Compute Shaders) работает на мобиле начиная с Metal (iOS 12+) и Vulkan (Android API 24+). На старых устройствах VFX Graph недоступен — нужен fallback на Shuriken.
SpriteKit SKEmitterNode — для 2D-игр нативно на iOS. Простой, быстрый, без overhead Unity. Но ограниченный: нет Sub Emitters, нет custom shaders без Metal. Для несложных эффектов (огонь, дождь, конфетти) достаточно.
Какой инструмент выбрать для VFX в мобильной игре?
Если проект кросс-платформенный, берите Unity Shuriken. Для iOS-only 2D-игр хватит SpriteKit. Если нужны уникальные эффекты с полным контролем — пишите кастомные шейдеры на Metal. Наша команда гарантирует, что выбранный стек не упрётся в ограничения GPU на целевых устройствах.
Бюджет частиц и GPU ограничения
На мобильных GPU (Apple A-серия, Adreno, Mali) bottleneck часто не в числе частиц, а в overdraw — количестве раз, которое один пиксель экрана перерисовывается за кадр.
Полупрозрачные частицы с аддитивным blending (Additive shader mode) дают overdraw кратно числу слоёв. На взрыве из 5000 частиц в центре экрана реальный overdraw может быть 50–100x. Это убивает fill rate даже на A15.
Стратегии снижения:
- Texture Atlasing: все спрайты частиц — в один атлас 512×512 или 1024×1024. Минус drawcall на каждую смену текстуры
- Billboard imposters: для объёмных эффектов (облако взрыва) — quad с запечённой текстурой вместо сотен сфер
- LOD для частиц: на расстоянии / при низком fps — уменьшить maxParticles вдвое через QualitySettings.particleRaycastBudget или кастомный LOD-менеджер
// Unity: динамический LOD системы частиц по FPS
public class ParticleLODManager : MonoBehaviour {
[SerializeField] private ParticleSystem targetSystem;
private ParticleSystem.MainModule _main;
private float _fpsTimer;
void Start() {
_main = targetSystem.main;
}
void Update() {
_fpsTimer += Time.deltaTime;
if (_fpsTimer < 1f) return;
_fpsTimer = 0;
float fps = 1f / Time.smoothDeltaTime;
if (fps < 45f) {
_main.maxParticles = Mathf.Max(100, _main.maxParticles / 2);
} else if (fps > 58f && _main.maxParticles < originalMax) {
_main.maxParticles = Mathf.Min(originalMax, _main.maxParticles * 2);
}
}
}
Почему overdraw — главный враг производительности?
GPU-симуляция через VFX Graph работает в 4 раза быстрее CPU-симуляции на A14 Bionic, но overdraw съедает этот выигрыш. При аддитивном смешении каждый пиксель может перерисовываться десятки раз. Чтобы этого избежать, мы применяем Texture Atlasing и сокращаем количество частиц с высоким альфа-наложением.
Кастомные шейдеры для мобильных VFX
Встроенные Unity шейдеры для частиц (Particles/Standard Unlit) безопасны, но ограничены. Для dissolve-эффекта, heat distortion, energy shield — нужен кастомный шейдер.
На мобиле правила жёсткие: нет discard в шейдере (ранний Z-test ломается, fill rate падает), минимум texture samples, избегаем dependent texture reads. Shader Model 2.0 как baseline для широкого охвата.
Пример простого distortion-эффекта для взрыва (Unity HLSL):
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _NoiseTex;
float _DistortionStrength;
float _FadeEdges;
fixed4 frag (v2f i) : SV_Target {
float2 noise = tex2D(_NoiseTex, i.uv + _Time.y * 0.3).rg * 2 - 1;
float2 distortedUV = i.uv + noise * _DistortionStrength * i.color.a;
float edge = 1 - saturate(distance(distortedUV, float2(0.5, 0.5)) * _FadeEdges);
fixed4 col = tex2D(_MainTex, distortedUV) * i.color;
col.a *= edge;
return col;
}
ENDCG
i.color.a — это alpha частицы от Unity Particle System, синхронизируется с lifetime. Distortion затухает вместе с частицей автоматически.
Эффекты на SpriteKit: огонь и конфетти
SKEmitterNode настраивается либо в редакторе Xcode (.sks файл), либо программно. Программно — предпочтительно для динамических параметров:
func makeFireEmitter() -> SKEmitterNode {
let emitter = SKEmitterNode()
emitter.particleTexture = SKTexture(imageNamed: "spark")
emitter.particleBirthRate = 120
emitter.particleLifetime = 1.2
emitter.particleLifetimeRange = 0.4
emitter.particleSpeed = 80
emitter.particleSpeedRange = 40
emitter.emissionAngle = .pi / 2 // вверх
emitter.emissionAngleRange = .pi / 8
emitter.particleScale = 0.15
emitter.particleScaleSpeed = -0.1
emitter.particleAlphaSpeed = -0.8
emitter.particleColorSequence = SKKeyframeSequence(
keyframeValues: [SKColor.yellow, SKColor.orange, SKColor.red, SKColor.clear],
times: [0, 0.3, 0.7, 1.0]
)
emitter.particleBlendMode = .add
return emitter
}
.add blending — аддитивное смешение. Огонь и искры выглядят светящимися. Не используем для дыма и пыли — там нужен .alpha.
Инструменты профилирования GPU
Xcode Metal Debugger — frame capture для Metal-игр. Видно каждый draw call, текстуры, overdraw visualization. Для Unity на iOS: через Xcode GPU Frame Debugger при подключении через USB.
Android GPU Inspector (AGI) — от Google для Adreno и Mali. Frame Profiler показывает pipeline stages, где GPU ждёт.
Unity Profiler — встроенный, покажет время CPU/GPU на рендер каждого эффекта. Rendering → ParticleSystem.Update занимает > 2ms — смотрим на CPU-симуляцию и снижаем maxParticles или переходим на GPU Mode.
Что входит в работу
- Разработка кастомных шейдеров под целевую платформу
- Оптимизация existing систем частиц (LOD, атласинг, overdraw)
- Интеграция в игровой движок (Unity, SpriteKit, кастомный)
- Профилирование и настройка под слабые устройства
- Документация по параметрам и поддержка
Процесс работы
Технический арт-дирекшн: какие эффекты нужны, их частота на экране одновременно, целевые устройства. Разработка шейдеров и систем частиц в редакторе с профилированием на слабом Android-девайсе. Настройка LOD-системы. Интеграция в игровой движок, тест на тепловые throttling (10-минутная игровая сессия с анализом температуры).
Ориентиры по срокам
3–5 рабочих дней на базовый набор VFX (3–5 типов эффектов). Сложная кастомная система на Metal Compute Shaders — от 2 недель. Конкретная стоимость рассчитывается индивидуально после анализа ваших требований. Оценим ваш проект: свяжитесь с нами для предварительного анализа. Получите консультацию по выбору инструмента для ваших эффектов.







