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

Какие знаешь ограничение Dynamic Batching?

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

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

🐱
claude-haiku-4.5PrepBro AI21 мар. 2026 г.(ред.)

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

# Ограничения Dynamic Batching

Отличный вопрос, который показывает знание low-level оптимизации. Dynamic Batching — это одна из ключевых техник оптимизации в Unity, но у неё есть множество ограничений, которые разработчики часто упускают.

Что такое Dynamic Batching

Dynamic Batching объединяет draw calls для объектов, которые используют один и тот же материал, в один call. Вместо:

DrawCall 1: Mesh (Box)
DrawCall 2: Mesh (Box)
DrawCall 3: Mesh (Box)

Получаем:

DrawCall 1: Meshes (Box, Box, Box) — объединены

Это уменьшает CPU overhead, но не бесплатно — есть CPU cost на объединение.

Основные ограничения

1. Размер вертексов

Ограничение: Максимум 900 вертексов на batched объект (для трёхмерных моделей)

// ❌ Не батчится — модель имеет 2000 вертексов
public class ComplexEnemy : MonoBehaviour {
    // Model с 2000 вертексов
    // Будет отдельный draw call, несмотря на попытку батчинга
}

// ✅ Батчится — модель оптимизирована
public class SimpleEnemy : MonoBehaviour {
    // Model с 800 вертексов
    // Может быть объединена с другими объектами
}

Для UI вроде Image/Text это 300 вертексов (limit меньше).

2. Материалы и свойства

Ограничение: Объекты должны использовать ОДИН и ТОТ ЖЕ материал (включая текстуры)

// ❌ Не батчится — разные материалы
var enemy1 = new GameObject("Enemy");
var renderer1 = enemy1.AddComponent<MeshRenderer>();
renderer1.material = new Material(redMaterial); // Red material

var enemy2 = new GameObject("Enemy");
var renderer2 = enemy2.AddComponent<MeshRenderer>();
renderer2.material = new Material(blueMaterial); // Blue material

// ✅ Батчится — одинаковые материалы
renderer1.material = sharedMaterial;
renderer2.material = sharedMaterial; // Один shared материал

Важно: Даже если использовать один материал, но менять его properties (color, texture):

// ❌ Нарушает батчинг — изменение material properties
renderer1.material.color = new Color(1, 0, 0); // Red
renderer2.material.color = new Color(0, 1, 0); // Green
// Это создаёт две разные material instances

// ✅ Правильно — использовать MaterialPropertyBlock
var mpb = new MaterialPropertyBlock();
mpb.SetColor("_Color", new Color(1, 0, 0));
renderer1.SetPropertyBlock(mpb);

var mpb2 = new MaterialPropertyBlock();
mpb2.SetColor("_Color", new Color(0, 1, 0));
renderer2.SetPropertyBlock(mpb2);
// Материал остаётся shared, меняется только блок свойств

3. Transform связность

Ограничение: Объекты в одной batch должны находиться рядом в иерархии Unity (для vertex-bound батчинга) или иметь определённое расположение в памяти

// ❌ Плохо для батчинга — объекты в разных местах иерархии
var parent1 = new GameObject("Parent1");
var child1 = new GameObject("Enemy");
child1.transform.parent = parent1.transform;

var parent2 = new GameObject("Parent2");
var child2 = new GameObject("Enemy");
child2.transform.parent = parent2.transform;

// ✅ Лучше — общий parent
var parent = new GameObject("Enemies");
child1.transform.parent = parent.transform;
child2.transform.parent = parent.transform;

4. Рендеринг очерёдность

Ограничение: Батчинг работает только для объектов, которые рендерятся последовательно

Если в очереди рендеринга:

1. Enemy (DrawCall 1)
2. Particle Effect (DrawCall 2)
3. Enemy (DrawCall 3) ← Не батчится с #1, потому что между ними другой DrawCall

5. Сортировка по глубине (Depth sorting)

Ограничение: Если камера требует сортировки по глубине (orthographic UI), динамический батчинг может не работать или работать хуже

6. Lighting и Shadows

Ограничение: Объекты с разными light probes или shadow settings не батчатся вместе

// ❌ Разные light probes
renderer1.probeAnchor = probe1;
renderer2.probeAnchor = probe2;
// Не батчатся

// ✅ Один light probe
renderer1.probeAnchor = probe1;
renderer2.probeAnchor = probe1;
// Могут батчиться

7. Scale и Rotation

Ограничение: Для некоторых шейдеров, особенно с vertex animation, негативный scale может предотвратить батчинг

// ❌ Может сломать батчинг
transform.scale = new Vector3(-1, 1, 1); // Negated scale

// ✅ Лучше решение
transform.scale = Vector3.one;
// Флип сделать в шейдере или отдельной текстуре

Практические советы

Профилирование

// Используй Frame Debugger в Unity Editor
// Window > Frame Debugger
// Там видишь exactно какие DrawCalls есть и почему они не батчатся

// Или код:
var materials = GetComponent<MeshRenderer>().sharedMaterials;
Debug.Log($"Material count: {materials.Length}");

Оптимизация для батчинга

  1. Используй SharedMaterial:
// ❌ Плохо
renderer.material.color = color; // Создаёт новый Material instance

// ✅ Хорошо
renderer.sharedMaterial = enemyMaterial;
var mpb = new MaterialPropertyBlock();
mpb.SetColor("_Color", color);
renderer.SetPropertyBlock(mpb);
  1. Комбинируй меши:
// Если много мелких объектов с одним материалом,
// рассмотри их комбинирование в один меш
public void CombineMeshes(GameObject[] objects) {
    var combine = new CombineInstance[objects.Length];
    for (int i = 0; i < objects.Length; i++) {
        combine[i].mesh = objects[i].GetComponent<MeshFilter>().mesh;
        combine[i].transform = objects[i].transform.localToWorldMatrix;
    }
    var combinedMesh = new Mesh();
    combinedMesh.CombineMeshes(combine);
    GetComponent<MeshFilter>().mesh = combinedMesh;
}
  1. Используй Static Batching для неподвижных объектов:
// Static batching не имеет ограничений по вертексам,
// но объект не может двигаться
GameObject.staticBatchingFlags = StaticBatchingFlags.Objects;

Когда батчинг НЕ важен

  • GPU-bound сценарии (проблема в графике, не в CPU)
  • Когда draw calls уже <1000 в frame
  • На высокопроизводительных машинах (PC, консоли)
  • Когда один big batch хуже многих маленьких (GPU memory pressure)

Итог

Dynamic Batching — это мощный инструмент оптимизации CPU, но требует понимания его ограничений. Не всегда это лучший выбор. Иногда лучше:

  • Static Batching для неподвижного content
  • GPU Instancing для повторяющихся объектов
  • Просто хороший код без микро-оптимизаций

Профилируй, чтобы знать, где реальная проблема!