Как снизишь колличество draw calls?
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Стратегии оптимизации Draw Calls в Unity
Оптимизация draw calls (вызовов отрисовки) — одна из ключевых задач для достижения высокой производительности рендеринга, особенно на мобильных платформах или в проектах с высокой геометрической сложностью. Каждый draw call — это команда графическому API (OpenGL, Vulkan, DirectX) на отрисовку группы мешей с определёнными материалами. Чем их меньше, тем лучше производительность. Вот моя комплексная стратегия по их снижению.
Основные принципы и анализ
Сначала я анализирую текущую ситуацию с помощью Frame Debugger и Profiler (раздел Rendering). Эти инструменты показывают:
- Количество draw calls на кадр
- Причины их разбиения (разные материалы, динамические батчи, прозрачные объекты)
- Статистику по батчингу (статическому и динамическому)
На основе этого анализа я применяю комбинацию методик.
1. Статический батчинг (Static Batching)
Для неподвижных объектов в сцене я использую статический батчинг. В инспекторе объекта включаю Static флаг (хотя бы для Rendering Static). Unity объединит меши таких объектов в один большой меш при сборке, что сократит draw calls до минимума.
Важные нюансы:
- Увеличивает потребление памяти (хранит объединённую геометрию)
- Не работает для объектов с уникальными материалами на экземпляр (например, разные текстуры)
- Требует отметки объектов как статических до сборки
// Пример: скрипт для принудительной отметки группы объектов как статических
void MarkChildrenAsStatic(GameObject parent)
{
foreach (Transform child in parent.transform)
{
child.gameObject.isStatic = true;
}
Debug.Log("Объекты отмечены как статические");
}
2. Динамический батчинг (Dynamic Batching)
Unity автоматически батчит небольшие динамические меши с одним материалом. Чтобы это работало:
- Меши должны содержать менее 300 вертексов
- Использовать один и тот материал
- Не использовать масштабирование с отрицательными значениями
- Для 2D спрайтов — использовать Sprite Atlas
Для максимальной эффективности динамического батчинга я:
- Контролирую количество вертексов в моделях
- Убеждаюсь, что материалы инстанциируются корректно
- Для UI элементов использую Canvas с правильными настройками (например, не перерисовываю весь canvas без необходимости)
3. Объединение материалов (Material Atlasing)
Одна из главных причин разбиения батчей — разные материалы. Я решаю это:
- Атласирование текстур: объединяю несколько мелких текстур в одну большую (для 2D — Sprite Atlas, для 3D — создаю UV-развёртки в пределах одного атласа)
- Использование GPU Instancing: для объектов с одинаковым мешем и материалом, но разными трансформациями
// Пример активации GPU Instancing в материале через код
Material material = GetComponent<Renderer>().material;
material.enableInstancing = true;
- Создание мастер-материалов: вместо множества мелких материалов создаю один универсальный с параметрами, изменяемыми через скрипт
4. Оптимизация прозрачных объектов и шейдеров
Прозрачные объекты (Alpha Blending) не батчатся с непрозрачными и часто сортируются, что увеличивает draw calls. Я:
- Минимизирую перекрывающиеся прозрачные объекты
- Использую Alpha Testing вместо Blending там, где возможно
- Оптимизирую сложные шейдеры, удаляю ненужные проходы (passes)
5. Уровень детализации (LOD) и Occlusion Culling
Для сложных сцен:
- LOD Group: создаю упрощённые версии моделей для дальнего расстояния
- Occlusion Culling: исключаю из рендера объекты, не видимые камере
6. Оптимизация UI
UI Canvas — частый источник проблем:
- Разделяю UI на несколько Canvas (статический и динамический)
- Для часто изменяемых элементов использую отдельный Canvas
- Минимизирую перерисовку (rebuild) UI
7. Скриптовая оптимизация
В коде я:
- Минимизирую изменения материалов во время выполнения
- Использую MaterialPropertyBlock для изменения свойств материала без создания нового инстанса
// Пример использования MaterialPropertyBlock
Renderer renderer = GetComponent<Renderer>();
MaterialPropertyBlock props = new MaterialPropertyBlock();
props.SetColor("_Color", Color.red);
renderer.SetPropertyBlock(props);
Комплексный подход
На практике я комбинирую эти методы:
- Анализирую сцену через Frame Debugger
- Статичные объекты — Static Batching
- Динамические объекты с одним материалом — оптимизирую под Dynamic Batching
- Повторяющиеся объекты — GPU Instancing
- Разные текстуры — объединяю в атласы
- Сложные сцены — внедряю LOD и Occlusion Culling
- UI — разделяю Canvas
Такой подход позволяет сократить draw calls на 50-80% в большинстве проектов. Ключ — постоянный мониторинг через Profiler и итеративная оптимизация на всех этапах разработки.