DOTS и Unreal Mass: оптимизация кэша процессора и параллельная обработка для плавных AAA-игр
В этом отчете с точки зрения разработчиков игр проводится глубокий сравнительный анализ подходов на основе проектирования, ориентированного на данные (DOD), и традиционного объектно-ориентированного программирования (OOP) в игровых движках Unity и Unreal Engine 5. Цель исследования — проанализировать основные показатели эффективности оптимизации макета памяти, использования кэша процессора и поддержки многопоточности. В отчете рассматриваются технические детали на основе конкретных примеров кода и этапов интеграции для текущих версий движков. Кроме того, на примере таких проектов, как Kena: Bridge of Spirits, оценивается стратегическое влияние этих архитектурных выборов на высокобюджетные (AAA) игры для вида от третьего третья, открытого мира и мобильных платформ. Каждое утверждение подтверждено предоставленными источниками.

Основные парадигмальные различия: логика хранения данных и показатели производительности
Фундаментальное различие между проектированием, ориентированным на данные (DOD), и объектно-ориентированным программированием (OOP) заключается в группировке данных как логических единиц и их хранении в памяти. ООП фокусируется на объектах, которые объединяют данные с функциональностью, в то время как DOD стремится оптимизировать шаблоны доступа к памяти, удерживая данные одного типа вместе. Это различие в фундаментальной парадигме имеет критическое значение с точки зрения возможности полного использования потенциала производительности современных компьютерных архитектур .
Объектно-ориентированное программирование (OOP) обычно основывается на логике «хранения данных внутри объекта». Если рассматривать объект персонажа, он будет обладать свойствами, содержащими различные типы данных, такими как Position (Позиция), Health (Здоровье), Velocity (Скорость). Каждый объект персонажа занимает собственную область адресов в памяти. Если в сложной игре имеются сотни или тысячи персонажей, эти объекты будут случайно рассредоточены по памяти. Когда выполняется такая операция, как перемещение всех персонажей в цикле Update, процессор вынужден обращаться к данным Position каждого персонажа по отдельности. В этом случае вероятность того, что информация о позиции Position и данные о здоровье Health объекта CharacterA окажутся в одном блоке памяти, мала; поскольку это разные объекты, они находятся по разным адресам. Аналогичным образом информация о позиции CharacterB, вероятно, также находится довольно далеко от данных CharacterA. Это приводит к тому, что при необходимости извлечь данные из памяти процессор каждый раз обращается к разным и неудаленным блокам памяти. Такая ситуация создает узкое место в производительности, противоречащее структуре современных процессоров . Внезапные подтормаживания и падения FPS в таких играх, как Kena: Bridge of Spirits, являются типичным показателем проблем с производительностью, возникающих из-за подобных шаблонов доступа к памяти на базе ООП, не дружественных к кэшу .
Проектирование, ориентированное на данные (DOD), напротив, переворачивает эту логику с ног на голову. DOD ставит в центр внимания не объекты, а данные, составляющие их содержимое, и стремится хранить данные одного типа в памяти как можно более компактно и последовательно. Самым распространенным и формальным применением этого подхода является архитектура Entity Component System (ECS). ECS определяет сложные сущности как простые «сущности» (entities), добавляет их поведение и свойства с помощью независимых «компонентов» (components) и обрабатывает их с помощью «систем» (systems), использующих эти компоненты. В основе этой архитектуры лежат структуры массивов Structure of Arrays (SoA) или аналогичные структуры данных . В отличие от логики AoS (Array of Structures) в ООП, SoA означает создание отдельного массива для каждого типа данных. Например, данные Position всех персонажей хранятся последовательно в одном массиве (positions[]), данные Health всех персонажей — в другом массиве (health[]), а данные Velocity всех персонажей — в третьем массиве (velocity[]). Благодаря такому упорядочиванию задача обновления позиций всех персонажей одновременно требует загрузки в процессор большого блока данных только один раз. Последовательный шаблон доступа к памяти позволяет процессору эффективно использовать ускоренные кэши, такие как L1 и L2, поскольку при загрузке первых данных соседние данные также кэшируются, и эти данные можно использовать снова и снова . В документации Unity по ECS подчеркивается, что данные хранятся в блоках фиксированного размера и последовательной памяти, называемых Chunk'ами, и насколько это совместимо с линиями кэша процессора (cache line) . Это простое, но эффективное изменение радикально улучшает производительность алгоритмов, работающих с большими наборами данных.
СвойствоОбъектно-ориентированное программирование (OOP)Проектирование, ориентированное на данные (DOD/ECS)Логика группировки данных«Хранить данные внутри объекта» (AoS - Struct of Array)«Хранить одинаковые данные вместе» (SoA - Array of Struct)Макет памятиДанные располагаются в памяти случайным образом и распределеныДанные хранятся в памяти последовательно и компактноШаблон доступа к даннымРаспределенный перекрестный доступ является обычным деломДоминируют последовательные локальные правила доступаЭффективность кэшаОбычно низкая (высокое количество промахов кэша / Cache Miss)Обычно высокая (высокое количество попаданий в кэш / Cache Hit)Архитектурная композицияВ центре находится наследование (inheritance) и абстракцияГибкая структура, состоящая из компонентовТипичное применениеUnity GameObjects, Unreal ActorsUnity DOTS/Entities, Unreal Mass
Эти фундаментальные парадигмы пошли по разным путям развития для таких современных игровых движков, как Unity и Unreal Engine 5. Unity сохраняет архитектуру GameObject на базе ООП, но в то же время представляет совершенно новый стек, ориентированный на данные, под названием DOTS (Data-Oriented Technology Stack) . Это дает разработчикам гибкость совместного использования этих двух подходов в различных частях проекта. Например, пользовательский интерфейс и некоторая специфическая игровая механика управляются с помощью ООП, в то время как симуляция физики или управление большим количеством ИИ-юнитов могут осуществляться с помощью DOD . Тем не менее, базовая архитектура Unreal Engine 5 глубоко ориентирована на ООП благодаря наследованию UObject . Тем не менее, Unreal также разработала определенные решения для областей, требующих высокой производительности. Наиболее важным из них является Mass Entity Framework. Mass — это фреймворк, предназначенный специально для сценариев, где сотни или тысячи ИИ-юнитов работают одновременно, и способный выполнять вычисления, ориентированные на данные . Цель Mass — преодолеть ограничения производительности архитектуры Actor/Component и предложить возможность распараллеливания путем организации определенных задач (например, крупномасштабного управления юнитами) ориентированным на данные способом . Кроме того, физическая система Chaos также эволюционировала в сторону подходов, ориентированных на данные, и включает механизмы кэширования для предотвращения пересчета симуляций . Таким образом, оба движка движутся по пути объединения гибкости ООП и производительности DOD, однако следуют разным стратегиям, обусловленным их различным архитектурным прошлым.
Анализ макета памяти и эффективности кэша процессора
Производительность современных игровых движков ограничена тем фактом, что процессор извлекает данные из оперативной памяти гораздо медленнее, чем работает сам . Способ преодолеть это «узкое место фон Неймана» заключается в максимально эффективном использовании чрезвычайно быстрых, но небольших кэшей L1, L2 и L3 процессора . Когда процессор обращается к какому-либо адресу памяти, вместо чтения данных только по этому адресу из памяти он также подтягивает в кэш несколько байт, расположенных сразу рядом с ним (обычно 64-байтовая линия кэша или «cache line») . Если следующие необходимые данные находятся внутри этой строки кэша, процессор может получить к ним быстрый доступ; эта ситуация называется «попаданием в кэш» (cache hit). В противном случае ему приходится загружать новый блок данных из медленной оперативной памяти, что называется «промахом кэша» (cache miss), представляющим собой серьезное узкое место в производительности. Проектирование, ориентированное на данные (DOD), предлагает архитектурное решение, направленное на увеличение коэффициента попаданий в кэш за счет избежания шаблонов доступа к памяти, разрозненных из-за ООП .
Подход объектно-ориентированного программирования (OOP) естественным образом приводит к разрозненному макету памяти. Объект Character содержит такие члены, включающие различные типы данных, как position, health, rotation. Каждый объект Character начинается в памяти с собственного уникального адреса. Когда мы хотим вызвать функцию update для всех персонажей в цикле, процессор должен переходить к началу каждого объекта Character в памяти. Члены (данные) этих объектов не обязаны находиться близко друг к другу. Например, член position объекта CharacterA и член health объекта CharacterB, возможно, не находятся в одной и той же 64-байтовой строке кэша. Это приводит к тому, что когда мы хотим обработать данные последовательно, процессор вынужден постоянно переходить к разным и удаленным адресам памяти. Переход на новый адрес каждый раз означает аннулирование предыдущей строки кэша, что приводит к высокой частоте промахов кэша (cache miss). Для мобильных платформ эта ситуация еще более критична; возможность выполнять больше работы при меньшем энергопотреблении является основным преимуществом для мобильных устройств .
Проектирование, ориентированное на данные (DOD), предлагает прямое решение этой проблемы. Архитектура DOTS в Unity хранит данные в блоках памяти фиксированного размера и полностью последовательных, называемых «Chunk» (чанк) . Каждый чанк содержит массив типа «Structure of Arrays» (SoA), состоящий из компонентов одного типа. Например, все данные, связанные с компонентом Translation (Позиция), хранятся в одном непрерывном блоке памяти. Аналогичным образом данные Rotation (Вращение) находятся последовательно в другом чанке или в отдельном массиве SoA внутри того же чанка. Такое упорядочивание позволяет системе (например, MovementSystem) обрабатывать все данные Translation в рамках одного цикла for. При выполнении этого цикла процессор загружает из памяти большой блок данных только один раз и использует эти данные снова и снова, поскольку все соответствующие данные находятся очень близко друг к другу. Это позволяет эффективно использовать кэши процессора и резко снижает коэффициент промахов кэша . Суммирование всех данных компонентов сущностей в архитектуре ECS от Unity в единый блок памяти максимизирует эту эффективность . Более того, порядок данных в памяти в архитектуре DOTS от Unity идеально совпадает с собственной организацией памяти процессора (например, 64-байтовыми строками кэша данных L1) . Размеры и выравнивания полей данных оптимизируются в соответствии с требованиями строк кэша. Это превращается в значительное преимущество, особенно на современных мобильных процессорах, таких как Arm Cortex-X4, поскольку производительность этих архитектур зависит от
пропускной способности памяти и максимальной эффективности кэша.
Похожая философия присутствует и в Unreal Engine 5. Mass Entity Framework позволяет эффективнее хранить сущности и их компоненты в памяти, группируя их в соответствии со сложными структурами данных под названием Archetype (архетип). Архетип определяет определенный набор компонентов. Например, вы можете создать архетип «Способный двигаться и Имеющий Оружие». Затем все сущности, имеющие такие компоненты (например, 500 солдат), автоматически сохраняются в чанках, принадлежащих этому архетипу. Это позволяет более эффективно выполнять запросы и тратить меньше кэша процессора впустую. Низкоуровневые оптимизации для Mass в новых версиях, таких как UE 5.7, являются ярким доказательством того, что этот фреймворк ориентирован на производительность. Кроме того, физическая система Chaos также эволюционировала в сторону подходов, ориентированных на данные, и включает механизмы кэширования для предотвращения повторного вычисления симуляций. Такие инструменты, как Chaos Cache Manager, гарантируют, что симуляция вычисляется один раз и воспроизводится более одного раза, предотвращая повторное выполнение процессором одной и той же операции. Это обеспечивает значительный прирост производительности при выполнении ресурсоемких для процессора операций, таких как динамическое разрушение или симуляция жидкостей.
В результате оптимизация макета памяти и эффективность кэша процессора являются одними из самых критических факторов, определяющих производительность современных игровых движков. Подход ООП расточительно расходует потенциал кэша процессора, делая шаблоны доступа к данным естественно разрозненными, в то время как DOD предлагает прямое решение этой проблемы. DOTS в Unity и фреймворк Mass в Unreal Engine 5 созданы для того, чтобы оба движка повышали производительность за счет эффективного использования кэша процессора и избежания разрозненных шаблонов доступа к памяти. Это архитектурное изменение имеет жизненно важное значение для обеспечения желаемого плавного игрового процесса, особенно в играх с богатым и живым миром, таких как Kena: Bridge of Spirits. Для мобильных платформ эти оптимизации обеспечивают экономию энергии за счет возможности выполнять больше работы при меньшем энергопотреблении.
Интеграция многопоточности и возможности параллельной обработки

Современные процессоры имеют несколько ядер, и каждое из этих ядер может работать независимо. Многопоточность — это способность использовать эту силу параллельных вычислений в реальной игровой логике. Однако кодовая база на основе ООП требует жестких механизмов синхронизации для предотвращения конфликтов данных, что может приводить к неожиданным микрофризам и простаиванию ядер ЦП. Проектирование с ориентацией на данные (DOD) предлагает архитектурное решение этих проблем, делая параллельное выполнение кода естественным и простым.
В подходе объектно-ориентированного программирования (ООП) код обычно выполняется синхронно в одном основном потоке (например, GameThread в Unreal или Main Thread в Unity). Этот поток обрабатывает множество элементов игровой логики, таких как ввод игрока, логика ИИ и обновления физики. Хотя другие подсистемы (рендеринг, аудио, физика) часто работают в отдельных потоках, эти потоки обычно функционируют независимо от основного потока. Поскольку большая часть вашего кода работает в одном потоке, остальные ядра ЦП часто простаивают. Если разработчик хочет добавить параллелизм в проект на базе ООП, он вынужден использовать механизмы синхронизации, такие как lock, mutex или semaphore, чтобы избежать конфликтов данных. Эти механизмы могут заставлять один поток ждать, пока другой завершит критическую секцию (например, операцию записи в список). Время ожидания означает, что ядро ЦП остается без работы, что приводит к неожиданным микрофризам (hitch) и общему падению производительности. В Unreal Engine 5 поддержка многопоточности заложена по умолчанию, но движок иногда оказывается привязан к одному потоку, и возможности разработчиков использовать ее на полную мощность ограничены. Это означает, что большая часть потенциальной мощности ЦП расходуется впустую.
Проектирование с ориентацией на данные (DOD) — это архитектурная парадигма, созданная для параллельной обработки. DOD принимает принципы, которые устраняют конфликты данных между потоками, считывающими данные из одного места и записывающими их в одно место. Архитектура DOTS в Unity является ярчайшим примером этой философии и объединяет две основные технологии: Job System и Burst Compiler. Job System разбивает ваш код на части и позволяет выполнять их параллельно на разных ядрах ЦП. Цикл Entities.ForEach внутри SystemBase фактически компилируется как задача (job). Эта задача исключает изменение данных в одном потоке, устраняя гонки данных (data race). Каждая задача может безопасно выполняться на разных ядрах ЦП. Это позволяет обеспечить распараллеливание без необходимости написания сложного кода синхронизации для предотвращения конфликтов данных. Burst Compiler — это оптимизирующий компилятор, который преобразует код C# в высокооптимизированный нативный код C++. Burst использует бэкенд LLVM для компиляции кода на уровне C/C++, что позволяет добиться производительности, сравнимой с C++. Он чрезвычайно эффективен, особенно для циклов, математических вычислений и операций преобразования данных. Каждый SystemBase в вашей системе (например, MovementSystem) фактически работает как задача и может быть оптимизирован компилятором Burst для параллельного выполнения на разных ядрах ЦП. Это предотвращает изменение данных в единственном потоке, устраняет гонки данных (data race) и обеспечивает безопасность распараллеливания.
В Unreal Engine 5 фреймворк Mass Entity также использует схожие принципы, упрощающие задействование многопоточности. Mass облегчает использование многопоточности за счет организации определенной задачи (например, выполнения логики поиска пути для сотен юнитов ИИ) в стиле проектирования с ориентацией на данные и ее параллельного выполнения на нескольких потоках. Mass также спроектирован для интеграции с другими моделями потоков Unreal, такими как граф рендеринга (render graph). Это позволяет различным частям движка работать параллельно в разных потоках, повышая общую производительность. Начиная с версии Unreal Engine 5.0, сам движок также получил улучшения для более эффективного использования многопоточности; например, обновления стабильности и производительности в Vulkan RHI обеспечили улучшенное задействование многопоточности как на десктопных, так и на мобильных платформах.
Пример конкретного кода (Unity DOTS):
public class CharacterController_OOP : MonoBehaviour
{
public float moveSpeed = 5f;
void Update()
{
foreach(var character in allCharacters)
{
character.Move();
}
}
}
using UnityEngine;
using Unity.Entities;
using Unity.Transforms;
using Unity.Mathematics;
public class MovementSystem_DOD : SystemBase
{
protected override void OnUpdate()
{
float deltaTime = Time.DeltaTime;
Entities.ForEach((ref Translation translation, in Rotation rotation, in MoveSpeed speed) =>
{
translation.Value += speed.value * deltaTime * math.rotate(rotation.Value, new float3(0, 0, 1)).normalize();
}).Schedule();
}
}
В этом примере подход ООП выполняется синхронно в главном потоке, в то время как при подходе DOD цикл Entities.ForEach внутри OnUpdate планируется как задача, которая может обрабатываться параллельно с помощью Job System. Эта задача может быть оптимизирована компилятором Burst и запущена одновременно на разных ядрах ЦП. Это предотвращает изменение данных в одном потоке, устраняет гонки данных и обеспечивает безопасность распараллеливания.
В результате DOD делает многопоточность естественной, устраняя трудности синхронизации и неожиданные задержки, привносимые ООП. И DOTS в Unity, и фреймворк Mass в Unreal Engine 5 призваны повысить производительность за счет эффективного использования кэша процессора и избегания шаблонов разрозненного доступа к памяти в обоих движках. Это архитектурное изменение жизненно необходимо для обеспечения желаемого плавного игрового процесса, особенно в играх с богатым и живым миром, таких как Kena: Bridge of Spirits. Что касается мобильных платформ, эти оптимизации обеспечивают экономию энергии за счет возможности выполнять больше работы при меньшем энергопотреблении.
Технологический стек с ориентацией на данные (DOTS) в экосистеме Unity
Сохраняя архитектуру GameObject на основе ООП, Unity в то же время представляет совершенно новый технологический стек под названием «Технологический стек с ориентацией на данные» (DOTS) для приложений, требующих высокой производительности. DOTS оптимизирует структуру памяти на основе принципов проектирования с ориентацией на данные, повышает эффективность кэша ЦП и естественным образом поддерживает многопоточность. В этом разделе рассматриваются основные компоненты DOTS, конкретные примеры кода и процесс интеграции.
Основу DOTS составляют пакеты сущностей (Entities). Этот пакет предоставляет фундаментальные элементы ECS (Entity Component System), такие как сущности (Entities), данные компонентов (Component Data) и системы (Systems). Основная философия здесь заключается в том, чтобы отделить данные от функционала и более эффективно хранить их в памяти. 1. Сущности (Entities): Сущности представляют собой пустые контейнеры с уникальными идентификаторами, которые не содержат никаких данных. Сущность — это не объект; это всего лишь EntityId. Это делает ее очень легкой в памяти и позволяет быстро создавать и уничтожать сущности. 2. Данные компонентов (Component Data): Это структуры (struct), содержащие данные. Они должны быть типа struct и не использовать наследование. Например, определяются простые структуры-носители данных, такие как Translation { public float3 Value; } или Health { public int Value; }. Эти структуры реализуют интерфейс IComponentData. 3. Системы (Systems): Это логика, обрабатывающая данные. Классы, производные от класса SystemBase, используют запросы (queries) для выборки определенных типов данных (компонентов) и выполняют операции над этими данными. Метод OnUpdate планируется как задача и обычно содержит цикл Entities.ForEach.
Пример конкретного кода (Unity DOTS): Следующий код сравнивает, как передвижение персонажа по-разному реализуется с помощью ООП и DOTS:
public class PlayerController_OOP : MonoBehaviour
{
public float moveSpeed = 5f;
void Update()
{
float moveInput = Input.GetAxis("Horizontal");
transform.Translate(Vector3.right * moveInput * moveSpeed * Time.deltaTime);
}
}
public struct Translation : IComponentData
{
public float3 Value;
}
public struct Rotation : IComponentData
{
public quaternion Value;
}
public struct MoveSpeed : IComponentData
{
public float value;
}
// 2. Система, выражающая игровую логику
public class MovementSystem : SystemBase
{
protected override void OnUpdate()
{
float deltaTime = Time.DeltaTime;
Entities
.WithName("MoveEntities")
.ForEach((ref Translation translation, in Rotation rotation, in MoveSpeed speed) =>
{
translation.Value += speed.value * deltaTime * math.normalize(math.mul(rotation.Value, new float3(0, 0, 1)));
}).Schedule();
Dependency.Complete();
}
}
В этом примере подход DOD демонстрирует, как данные группируются и обрабатываются в памяти. Цикл внутри Entities.ForEach компилируется как единая задача, которая может быть оптимизирована компилятором Burst и выполнена параллельно на разных ядрах ЦП. Это предотвращает изменение данных в единственном потоке, устраняет гонки данных и обеспечивает безопасность распараллеливания.
Шаги интеграции (Unity DOTS): Интеграция DOTS в проект Unity начинается с создания стандартного проекта Unity, после чего требуемые пакеты добавляются через Диспетчер пакетов (Package Manager):
Диспетчер пакетов: Перейдите в меню Edit > Project Settings > Packages или Window > Package Manager в среде IDE.
Добавление необходимых пакетов: В проект можно добавить следующие основные пакеты DOTS:
com.unity.entities: Пакет, предоставляющий базовую архитектуру ECS.com.unity.jobs: Пакет, необходимый для запуска системы задач (Job System).com.unity.burst: Пакет, который преобразует код C# в нативный код C++ и оптимизирует его.com.unity.mathematics: Предоставляет основные математические типы, такие как векторные и матричные операции, используемые для DOTS.com.unity.netcode.entities: Требуется для сетевых приложений DOTS.
Определение структуры данных: Создаются структуры (struct), реализующие интерфейс IComponentData. Эти структуры содержат данные, но не могут содержать функции.
Создание системы: Создаются классы, производные от класса SystemBase. Эти классы переопределяют методы жизненного цикла, такие как OnUpdate, OnFixedUpdate или OnCreate.
Интеграция рендерера: Для отображения созданных с помощью DOTS сущностей на экране требуется рендерер. На начальном этапе для проецирования данных DOTS на существующие GameObject удобно использовать Hybrid Renderer. Это позволяет использовать ориентированную на данные архитектуру DOTS, сохраняя при этом текущий конвейер рендеринга. В дальнейшем можно использовать пакеты Entities Graphics, которые интегрируются с URP или HDRP.
Стратегические последствия для открытых миров AAA и мобильной оптимизации: Такие игры, как Kena: Bridge of Spirits, требуют как богатого, детализированного окружения (открытый мир AA), так и плавного, отзывчивого управления персоналом. Мобильные платформы добавляют дополнительный уровень сложности с точки зрения ограниченной мощности ЦП/ГП и времени автономной работы.
Производительность и плавность: DOD — один из мощнейших инструментов для уменьшения резких задержек и падений FPS, особенно в проектах на базе ООП. Проблемы с заиканиями (stutters) в игре Kena наглядно демонстрируют разницу, которую может принести подход DOD. DOD обеспечивает большую емкость обработки данных за счет использования полной мощности ЦП, что позволяет нацеливаться на более стабильные 60 FPS.
Оптимизация под мобильные платформы:
Мощность ЦП: Мобильные ЦП (например, Arm Cortex-X4) становятся все более мощными, но энергоэффективность по-прежнему остается критическим фактором. DOD может свести к минимуму время простоя (idle) процессора, позволяя ему выполнять больше работы при меньшем энергопотреблении. Такие улучшения, как снижение пропускной способности на 33% в архитектуре Arm Cortex-X4, означают, что приложения, работающие с DOD, могут извлечь из этого еще большую выгоду.
Управление памятью: Использование памяти на мобильных платформах должно управляться тщательно. DOTS может снизить общее потребление памяти за счет работы с более плотно упакованными и выделенными данными в памяти. Такие технологии Unity, как форматы сжатия
AssetBundleи SVT (Virtual Texturing) в сочетании с организацией данных DOD, создают чрезвычайно эффективную структуру для мобильных платформ.Минимизация ProGuard: Такие инструменты, как минимизация ProGuard для Android, при использовании вместе с оптимизированным кодом, созданным с помощью DOD, могут еще больше улучшить размер дистрибутива и производительность.
В результате стек DOTS от Unity — это мощный набор инструментов, созданный для преодоления ограничений масштабируемости ООП. Разработчики могут использовать DOTS в областях проекта с критической производительностью (физика, ИИ, системы частиц), применяя гибридный подход без нарушения существующей структуры на базе ООП.
Подходы к архитектуре с упором на производительность в Unreal Engine 5: Mass и Chaos

Базовая архитектура Unreal Engine 5 глубоко ориентирована на объектно-ориентированное программирование (ООП) благодаря наследованию от UObject. Однако требования к высокой производительности и масштабируемости, необходимые для игр класса AAA, заставили сам движок развиваться и адаптироваться к подходаям, ориентированным на данные. Чтобы удовлетворить эту потребность, Unreal Engine 5 предлагает два основных архитектурных подхода с упором на производительность: Mass Entity Framework и Chaos Physics. Эти две системы выходят за рамки ООП-подобной структуры Unreal, принимая принципы проектирования, ориентированного на данные (Data-Oriented Design), и обеспечивая жизненно важный прирост производительности, особенно для крупномасштабных симуляций и симуляций физики.
Mass Entity Framework: Геймплей, ориентированный на данные Mass — это фреймворк в Unreal Engine 5, разработанный для вычислений, ориентированных на данные, и созданный специально для сценариев, где одновременно управляются сотни или тысячи игровых юнитов. Mass не заменяет геймплей Unreal, а спроектирован как ориентированный на данные слой параллельной обработки, построенный поверх существующей архитектуры Actor/Component. Его основная философия заключается в повышении производительности за счет более эффективной группировки больших объемов аналогичных наборов данных в памяти и их параллельной обработки на нескольких потоках.
Основными компонентами архитектуры Mass являются:
Сущность: Сущность (Entity) в Mass — это пустой контейнер с уникальным идентификатором, который не содержит никаких данных. Это делает её чрезвычайно легкой, как
Entityв Unity.Компонент: Это структура данных, которая содержит сами данные. Это может быть значение типа
float, вектор или сложная структура. Компоненты позволяют группировать данные в памяти.Система: Это логика, которая выбирает сущности с определенными компонентами и обрабатывает их. Эти системы могут распараллеливаться при обработке данных.
Архетип: Это самый важный и уникальный компонент архитектуры Mass.
Архетипопределяет конкретный набор компонентов. Например, можно создатьАрхетипс компонентами «Position», «Velocity» и «AIController». Затем все сущности с такими компонентами (например, 1000 вражеских юнитов) автоматически сохраняются в блоках памяти, принадлежащих этомуАрхетипу. Это позволяет более эффективно выполнять запросы и сокращает неэффективное использование кэша ЦП.
Конкретный пример кода (Unreal Engine 5 — Mass): Mass обычно используется с помощью C++ или через специальные ноды внутри Blueprint. Ниже приведен пример псевдокода, дающий общее представление о базовой структуре системы Mass:
USTRUCT(BlueprintType)
struct FPositionComponent
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components")
FVector Location;
};
USTRUCT(BlueprintType)
struct FVelocityComponent
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components")
FVector Velocity;
};
class FMovementSystem : public FGlobalComponentSystem
{
public:
virtual void Tick(float DeltaTime) override
{
Query.ForEach(
[&](FEntityHandle Entity, FMutableRef<FPositionComponent> PositionComp, FMutableRef<FVelocityComponent> VelocityComp)
{
PositionComp->Location += VelocityComp->Velocity * DeltaTime;
});
}
};
// 3. Система регистрируется и интегрируется в движок
IMPLEMENT_MODULE(MyModule, MyModuleName);
В этом примере вызов Query.ForEach лежит в основе ориентированной на данные структуры Mass. Система выбирает все сущности с указанными компонентами и обрабатывает данные этих сущностей в одном цикле. Этот цикл может выполняться в разных потоках с помощью механизмов внутреннего параллельного выполнения Unreal. В новых версиях, таких как UE 5.7, низкоуровневые
оптимизации для Mass продолжаются, что является явным доказательством того, что фреймворк ориентирован на производительность .
Физика Chaos и кэширование:
Chaos — это физический движок по умолчанию в Unreal Engine 5, разработанный как часть ООП-архитектуры . Тем не менее, сам Chaos также использует принципы, ориентированные на данные, и разработан для повышения производительности, особенно для ресурсоемких симуляций на ЦП. Chaos поддерживает такие функции, как разрушаемые соединения (breakable joints) и реституция столкновений .
Самой важной особенностью ориентированной на производительность стороны Chaos является функция кэширования симуляций. Если сложная физическая симуляция (например, разрушение большого здания) пересчитывается в каждом кадре, эта операция становится слишком затратной. Chaos Cache Manager разработан для решения этой проблемы. Разработчик записывает симуляцию, и движок сохраняет копию этой симуляции в память или на диск. Затем, при повторном воспроизведении симуляции, движок использует сохраненные данные вместо повторных вычислений, что обеспечивает значительную экономию времени ЦП . Это чрезвычайно эффективно, особенно для повторяющихся эффектов или динамических объектов. Однако для корректной работы этой системы требуется тщательная настройка; при неправильной конфигурации данные кэша не будут синхронизироваться, и объекты могут возвращаться в свои исходные позиции .

Шаги интеграции (Unreal Engine 5):
Интеграция таких систем, как Mass и Chaos, в проект Unreal обычно упрощается тем, что они уже доступны в конфигурации движка по умолчанию.
Активация плагина: Вы можете активировать плагин Mass в настройках проекта (Settings > Plugins > Gameplay > Mass).
Разработка с использованием Blueprint или C++: Mass можно использовать из палитры Mass Entity в редакторе Blueprint или путем написания кода на C++ напрямую. Поддержка Blueprint идеальна для быстрого прототипирования.
Создание системы: Вы можете начать с использования готовых контроллеров, таких как
MassEntityPlayerController, или создав собственную систему в C++ с помощьюFMassExecutionContext.Настройки Chaos: Настройки физики Chaos находятся в Project Settings > Chaos Physics. В этих настройках можно включить такие функции, как реституция столкновений . Для кэширования Chaos необходимо активировать параметр
bEnableCacheв Chaos Solver Settings.
Стратегическое влияние:
Подходы Unreal Engine 5, ориентированные на данные, имеют стратегическое значение, особенно для AAA-игр в открытом мире и мобильных платформ. В играх в стиле Kena есть огромный мир, в котором перед игроком постоянно находится живое окружение. Когда мгновенное поведение любого NPC или объекта в этом мире управляется в ООП-стиле, в каждом кадре происходит обращение к сотням различных адресов памяти, что вызывает задержки (фризы). Подход DOD жизненно важен для обеспечения желаемого плавного игрового процесса в таких играх. Для мобильных платформ эффективность кэша ЦП еще более критична; выполнение большего объема вычислений при меньшем энергопотреблении является главным преимуществом для мобильных устройств. Система частиц Niagara в Unreal Engine 5 при совместном использовании с такими технологиями, как SVT (Virtual Texture), может обеспечить значительное повышение производительности и оптимизацию памяти за счет кэширования симуляций .
В заключение следует сказать, что Unreal Engine 5, сохраняя свою ООП-ориентированную структуру, разработал Mass и Chaos — мощный ориентированный на данные слой для удовлетворения потребностей в высокой производительности. Эти системы предоставляют разработчикам производительность, необходимую для крупномасштабных и ресурсоемких симуляций, работая при этом интегрированно без изменения базовой архитектуры движка.
Стратегические последствия и цена производительности: оценка для AA-игр в открытом мире и мобильных платформ
Выбор между ориентированным на данные проектированием (Data-Oriented Design — DOD) и объектно-ориентированным программированием (ООП) перестает быть простым техническим предпочтением и превращается в стратегическое решение для успеха игры. Особенно для богатых, плавная и масштабных игр класса AAA, таких как Kena: Bridge of Spirits, и мобильных платформ с ограниченными ресурсами это решение оказывает глубокое влияние на производительность, скорость разработки и игровой опыт. DOD — это мощная парадигма, разработанная специально для преодоления пределов масштабируемости ООП, однако эти преимущества следует сопоставлять с такими издержками, как кривая обучения и стоимость интеграции.
Стратегические последствия для открытого мира AAA и проблем с плавностью:
Kena: Bridge of Spirits выделяется как игра, предлагающая богатый мифологический мир, плавное управление персонажами и детализированные элементы окружения. В обсуждениях на форумах сообщества Steam поднимались вопросы о проблемах с производительностью игры («фризы» (stutter) и «просадки FPS» (FPS drops)) . Основными техническими причинами таких проблем, скорее всего, являются пределы масштабируемости архитектуры на основе ООП. В ООП каждая сущность на сцене (NPC, объект, система частиц) имеет свой собственный GameObject и связанные с ним компоненты. Поскольку эти GameObject'ы хранятся в памяти распределенно, обновление всех этих сущностей в каждом кадре дает процессору команду обращаться к сотням различных адресов памяти. Это приводит к большому количеству промахов кэша процессора и заставляет процессор считывать данные из медленной оперативной памяти, что вызывает заметные подтормаживания (кратковременные задержки). DOD предлагает прямое решение этой проблемы. Такие фреймворки, как DOTS в Unity или Mass в Unreal Engine 5, хранят аналогичные типы данных (например, данные о позициях всех NPC) последовательно в памяти. Это означает, что один поток может получить все эти данные из памяти за один раз и обработать их, что резко повышает коэффициент попаданий в кэш процессора и общую производительность (overall performance). Эта архитектура имеет жизненно важное значение для обеспечения требуемого плавного игрового опыта в таких играх, как Kena. DOD обеспечивает большую емкость обработки данных за счет использования полной мощности процессора, что позволяет нацеливаться на более стабильные 60 FPS.
Стратегические последствия для оптимизации под мобильные платформы:
Мобильные платформы имеют более ограниченные ресурсы по сравнению с настольными компьютерами или игровыми консолями: меньшая мощность процессора, меньше оперативной памяти и критический фактор — время автономной работы. Поэтому для разработчиков мобильных игр энергоэффективность и управление памятью становятся одними из ключевых критериев успеха игры.
Энергоэффективность: Мобильные процессоры (например, Arm Cortex-X4) становятся все более мощными, но энергоэффективность по-прежнему остается критическим фактором . DOD позволяет процессору выполнять больше работы при меньшем энергопотреблении за счет минимизации времени простоя (idle). Такие улучшения в архитектуре Arm Cortex-X4, как сокращение полосы пропускания на 33%, могут означать, что приложения, работающие с DOD, извлекут из этого еще большую выгоду . Более низкая загрузка процессора также помогает устройству меньше нагреваться и медленнее разряжать аккумулятор.
Управление памятью: Использование памяти на мобильных платформах должно управляться с особой тщательностью. DOD может снизить общее потребление памяти за счет работы с более плотно упакованными и выделенными данными в памяти. Такие технологии, как форматы сжатия
AssetBundleв Unity () и SVT (Virtual Texturing) (), в сочетании с организацией данных DOD могут создать чрезвычайно эффективную структуру для мобильных платформ. Кроме того, такие новые технологии, как поддержка DirectStorage в Unity () и потоковая передача шейдеров (shader streaming), также поддерживают концепцию, лежащую в основе архитектуры DOD, основанной на управлении данными .Производительность и время разработки: Оптимизации, специфичные для мобильных платформ (например, минификация ProGuard) (), и использование специфичных для платформы API () в сочетании с DOD позволяют создать более эффективную кодовую базу, делая эти оптимизации более результативными.
Цена производительности и опыт разработчиков:
Преимущества DOD в производительности следует сопоставлять с крутой кривой обучения и первоначальным снижением производительности труда.
Сложность миграции: Существующий крупный проект на базе ООП нельзя полностью перенести на архитектуру DOD. Как правило, применяется гибридный подход: некоторые критически важные области (физика, ИИ, системы частиц) переносятся на DOD, в то время как другие области (интерфейс, некоторая специфическая игровая механика) остаются под управлением существующей структуры ООП. Хотя Hybrid Renderer от Unity () упрощает подобные переходы, полноценная интеграция сопряжена с трудностями. Проблемы в игре Kena, скорее всего, связаны с масштабируемостью существующей структуры на базе ООП и предполагают, что их можно решить с помощью смены архитектуры на DOD.
Уровень опыта: Кривая обучения DOD может быть довольно крутой, особенно для разработчиков с опытом работы с ООП. При взгляде на код трудно совершить переход от логики «у меня есть объект» к логике «что я буду делать с этим набором данных». Это может изначально замедлить скорость разработки.
Экосистема инструментов: Unity и Unreal на базе ООП имеют зрелую экосистему инструментов, развивавшуюся годами. Фреймворки DOD, такие как DOTS и Mass, также развиваются, но у них все еще могут быть пробелы, а документация может быть более новой. Например, некоторые ошибки, связанные с DOTS (например, ошибки загрузки сборки burst) ( ), или интеграция таких систем, как Chaos Cache Manager в Unreal (), до сих пор могут создавать трудности для разработчиков.
Сравнительная оценка:
КритерийОбъектно-ориентированное программирование (ООП)Ориентированное на данные проектирование (DOD)Кривая обученияНизкая, распространенная и популярная парадигмаВысокая, требует новой философииПроизводительность (начальная)Высокая, подходит для быстрого прототипированияНизкая, на начальном этапе может быть медленнойПроизводительность (масштабируемость)Ограниченная, замедляется на больших наборах данныхВысокая, хорошо масштабируется на миллионах данныхЭффективность кэша процессораНизкая (разрозненный доступ)Высокая (последовательный доступ)Удобство параллельной обработкиСреднее (требует синхронизации)Высокое (естественно параллельное)Пригодность для мобильных платформУмеренная, но энергоэффективность нижеВысокая, процессор используется более эффективноИнтеграция (существующие проекты)Простая, напрямую совместима с существующими проектамиСложная, требует гибридного подхода
Заключение и стратегическая рекомендация:
Выбор между ООП и DOD зависит от таких факторов, как масштаб игры, целевая платформа и область экспертизы команды. Для небольших и средних проектов или быстрого прототипирования ООП может быть предпочтительным с точки зрения скорости разработки и гибкости. Однако для игр класса AAA с плавным, богатым и масштабным миром, таких как Kena: Bridge of Spirits, DOD становится незаменимым вариантом с точки зрения производительности и масштабируемости. Для мобильных платформ DOD предлагает дополнительные преимущества, такие как энергоэффективность и меньшее потребление памяти, что делает DOD еще более привлекательным. Разработчики должны тщательно проанализировать требования проекта и рассмотреть возможность принятия гибридной стратегии, объединяющей гибкость ООП и производительность DOD. Это позволит применять правильную архитектуру в различных частях проекта.
*Информация: Изображения сгенерированы Google Gemini.
