← Назад к вопросам

Как снизишь колличество draw calls?

2.0 Middle🔥 222 комментариев
#Оптимизация#Рендеринг и графика

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Стратегии оптимизации 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);

Комплексный подход

На практике я комбинирую эти методы:

  1. Анализирую сцену через Frame Debugger
  2. Статичные объекты — Static Batching
  3. Динамические объекты с одним материалом — оптимизирую под Dynamic Batching
  4. Повторяющиеся объекты — GPU Instancing
  5. Разные текстуры — объединяю в атласы
  6. Сложные сцены — внедряю LOD и Occlusion Culling
  7. UI — разделяю Canvas

Такой подход позволяет сократить draw calls на 50-80% в большинстве проектов. Ключ — постоянный мониторинг через Profiler и итеративная оптимизация на всех этапах разработки.