Как Toca Boca создала высокопроизводительный масштабируемый рендеринг бэкенд

BERTRAND GUAY-PAQUET / TOCA BOCASenior Graphics Engineer
Mar 20, 2026
Toca Boca
Эта веб-страница была переведена с помощью машинного перевода для вашего удобства. Мы не можем гарантировать точность или надежность переведенного контента. Если у вас есть вопросы о точности переведенного контента, обращайтесь к официальной английской версии веб-страницы.

Чтобы удовлетворить требованиям производительности нашей амбициозной мобильной 3D многопользовательской игры, Toca Boca Days – особенно на устройствах начального уровня – нам нужно было внедрять инновации. В игре (сейчас на паузе) были обширные уровни и поддержка до 32 игроков с высоконастраиваемыми аватарами.

В конце 2022 года мы запустили нашу систему бэкенда Batch Renderer, разработанную на основе Unity’s BatchRendererGroup API. Эта новая система обеспечила значительное повышение производительности, которое мы продолжаем совершенствовать.

В этой статье я поделюсь своими мыслями об архитектуре системы, поскольку мы готовимся использовать ее в нашей предстоящей игре.

Обзор архитектуры данных

В общих чертах, наша система разделяет данные для GameObject и его компонента Renderer на три слоя.

Слой за слоем архитектура данных
Слой за слоем архитектура данных

В первом слое каждый компонент Renderer соответствует одному экземпляру обрезки. Этот слой содержит все данные, необходимые для определения видимости на основе плоскостей обрезки камеры, маски слоя и любой родительской группы LOD.

Второй слой представляет собой материалы каждого рендерера, где каждая пара рендерера и материала образует экземпляр отрисовки. Экземпляры отрисовки хранят данные, связанные с рендерингом, такие как сетка и материал.

Третий слой состоит из BatchRendererGroup батчей (отсюда и название Batch Renderer) и их инстансов. У каждой партии есть свой GraphicsBuffer , содержащий встроенные свойства на основе экземпляра, такие как матрица ObjectToWorld , а также необязательный набор свойств материала на основе экземпляра.

Набор свойств материала на экземпляр рендерера определяет его тип группы.

Toca Boca Days | Toca Boca
Множество книг со значениями свойств материалов для каждого экземпляра

Наша система хранит все данные на уровне CPU в компактной структуре данных с упорядочиванием массивов (SoA). Она использует типы данных, которые можно копировать, в стандартных контейнерах, где это возможно, что позволяет использовать высокопроизводительные задачи Burst для выполнения таких задач, как отбраковка экземпляров и генерация команд отрисовки. Эта архитектура позволяет системе эффективно обрабатывать большое количество экземпляров.

Свойства материала для каждого экземпляра

Чтобы назначить свойства материала для каждого экземпляра рендереру, мы добавляем компонент, ссылающийся на «набор свойств»ScriptableObject asset. Количество наборов свойств должно быть ограничено, поскольку каждый из них определяет отдельный тип пакетной обработки — экземпляры из разных пакетов не рендерируются вместе.

Для упрощения создания мы предоставляем компонент для установки начальных значений свойств экземпляров, а также настраиваемое окно Inspector. Без свойств для каждого экземпляра эти значения нужно было бы устанавливать в уникальные материалы, что снижало бы эффективность пакетной обработки.

Инспектор свойств материалов для каждого экземпляра
Инспектор свойств материалов для каждого экземпляра

Растяжка и скелеты

В Toca Boca Days, аватары имели обширные возможности настройки персонажей. Для поддержки разнообразной одежды и аксессуаров мы разделили обтянутые участки сетки каждого аватара на 17 компонентов Skinned Mesh Renderer (например, левая верхняя часть руки). Большинство предметов одежды добавляют дополнительные обтянутые компоненты Renderer, которые могут быстро накапливаться по мере увеличения количества игроков.

Toca Boca Days | Toca Boca
Аватары Toca Boca Days

Поскольку наши аватары сложны, мы избегаем их использования для карт теней, что было бы дорогостоящим. Вместо этого мы используем тени, похожие на пятна, и в большинстве случаев аватары рендерируются только один раз в кадр. Это означает, что мы не можем равномерно распределить стоимость встроенного в Unity вершинного скиннинга между несколькими командами отрисовки для одной сетки.

Вместо этого мы обрабатываем скиннинг непосредственно в шейдере вершин. Все матрицы скиннинга хранятся в одной глобальной переменной GraphicsBuffer, и каждый рендерер получает смещение в этот буфер для корректировки индексов костей для каждого вершины и извлечения соответствующих матриц скиннинга.

Смещение скелета сохраняется как BatchRendererGroup данные экземпляра, позволяющие нам объединять вызовы отрисовки для персонажей, использующих одну и ту же сетку (например, все правые плечи вместе), что повышает производительность.

Вычисление матриц скиннинга обычно требует вычислений количества рендереров × среднее количество костей на рендерер. Чтобы уменьшить это, мы объединяем два подхода:

Убедитесь, что все компоненты Renderer с кожаным натяжением в аватаре используют согласованные индексы костей – например, индекс кости 2 всегда относится к груди, даже для компонента Renderer правой ноги, который не ссылается на нее.

Предварительно обрабатывайте сетки для выявления уникальных наборов индексов костей и матриц исходного положения, в идеале, в результате чего на аватаре будет только один набор.

Компонент предварительной обработки компоновки скелета
Компонент предварительной обработки компоновки скелета

При таком подходе мы можем объединить скиннинг всех компонентов Skinned Mesh Renderer аватара в одну пару «анимационный скелет» и «рендерер-скелет».

Анимационные и рендерер-скелеты (показаны два рендерер-скелета)
Анимационные и рендерер-скелеты (показаны два рендерер-скелета)

На каждом кадре наш менеджер скелетов выполняет следующие действия:

Извлечение анимации: Задачи анимации извлекают текущие преобразования костей из анимационного скелета через API Игровые объекты API (Mecanim).

Вычисление поз: Задачи Burst генерируют анимационные матрицы поз из иерархии костей и извлеченных преобразований.

Сборка матриц скэнинга: Задачи Burst объединяют анимационные матрицы поз и матрицы исходных поз в матрицы скэнинга.

Загрузка на GPU: Новые матрицы скиннинга загружаются в глобальную память GraphicsBuffer используя вычислительный шейдер.

Этот процесс сложен, но очень эффективен: количество матриц обтекания уменьшается вдвое для голого аватара и в четыре или более раз при использовании одежды.

Заглядывая вперед

Разработка пользовательского рендеринга для Toca Boca Days и теперь его модернизация для Unity 6.3 оказалась полезной. Обновление до Unity 2022.3 прошло гладко, и наша система пакетного рендеринга продолжает обеспечивать высокую производительность для игр с обширными возможностями настройки персонажей и свойствами материалов для каждого экземпляра.

Полный контроль над генерацией команд отрисовки через BatchRendererGroup API позволяет использовать индивидуальные стратегии отсечения, такие как порталы окклюзии и пользовательское отсечение окклюзии, а также оптимизации анимации, такие как ограничение обновления матриц скиннинга в зависимости от близости камеры и важности.

Возможности расширения Unity в сочетании с производительными готовыми решениями, такими как Universal Render Pipeline (URP) и GPU Resident Drawer (с доступом к исходному коду), позволили нам достичь наших целей по производительности, сохраняя при этом высоко оптимизированный пользовательский рендеринговый конвейер.

Toca Boca Days | Toca Boca
Пакетный рендерер вернется

Toca Boca разрабатывает игру, о которой еще ничего не объявлено; следите за студией в Instagram, TikTok и YouTube для получения обновлений. Узнайте больше историй от разработчиков мобильных приложений Unity на нашем сайте страница мобильных решений и наш Центр ресурсов.