LYSC STUDIO

LIST
Cover

매스 엔티티(Mass Entity) 프레임워크를 활용한 대규모 군중 시뮬레이션 구현: 데이터 지향 설계(DOD)의 UE5 적용

·UE5 Engine

수만 명의 AI가 상호작용하는 대규모 군중 시뮬레이션은 어떻게 구현될까요? UE5의 매스 엔티티(Mass Entity) 프레임워크와 데이터 지향 설계(DOD) 패러다임을 통해 압도적인 퍼포먼스를 달성하는 방법을 살펴봅니다.

객체 지향 프로그래밍(OOP)의 한계와 데이터 지향 설계(DOD)의 부상

언리얼 엔진의 근간은 UObjectAActor로 대표되는 객체 지향 프로그래밍(OOP)입니다. 액터 안에 컴포넌트를 붙이고 캡슐화, 상속, 다형성을 활용하여 게임 로직을 구현하는 방식은 매우 직관적이고 생산성이 높습니다. 하지만 10,000명의 좀비가 뛰어다니는 군중 시뮬레이션을 상상해 봅시다. 10,000개의 액터가 매 프레임마다 Tick 함수를 호출하고, 각자의 메모리 주소에 흩어져 있는 변수들에 접근한다면, CPU는 캐시 미스(Cache Miss)로 인해 엄청난 병목을 겪게 됩니다.

이러한 성능의 벽을 부수기 위해 도입된 패러다임이 바로 데이터 지향 설계(Data-Oriented Design, DOD)이며, 언리얼 엔진 5에서 이를 구현한 시스템이 매스 엔티티(Mass Entity) 프레임워크입니다. Unity의 DOTS(Data-Oriented Technology Stack)와 유사한 개념으로, 데이터의 레이아웃을 최적화하여 CPU의 캐시 적중률(Cache Hit Rate)을 극대화하는 것이 핵심입니다.

매스 엔티티(Mass Entity)의 3요소: 엔티티, 프래그먼트, 프로세서

매스 엔티티 프레임워크는 기존의 Actor/Component 구조를 완전히 벗어난 ECS(Entity Component System) 아키텍처를 따릅니다.

  1. 엔티티(Entity): 고유한 ID(정수값)일 뿐입니다. 어떠한 로직이나 데이터도 직접 포함하지 않습니다.
  2. 프래그먼트(Fragment): 순수한 데이터의 묶음입니다(C++의 struct). 예를 들어 FTransformFragment는 위치, 회전, 스케일 데이터만 가지고 있고, FVelocityFragment는 속도 벡터만 가집니다. 구조체 안에는 어떠한 가상 함수(Virtual Function)도 없습니다.
  3. 프로세서(Processor): 로직을 담당하는 시스템입니다. 특정 프래그먼트 조합을 가진 엔티티들을 필터링하여 일괄 처리합니다. 예를 들어 UMovementProcessorFTransformFragmentFVelocityFragment를 가진 모든 엔티티를 찾아 속도에 따라 위치를 업데이트합니다.

메모리 레이아웃과 아키타입(Archetype) 청크

매스의 압도적인 성능은 데이터를 메모리에 배치하는 방식에서 나옵니다. 매스는 동일한 프래그먼트 조합을 가진 엔티티들을 아키타입(Archetype)으로 분류하고, 이들의 데이터를 연속적인 메모리 블록(Chunk)에 배열(Array) 형태로 압축하여 저장합니다.

프로세서가 연산을 수행할 때 메모리에 연속적으로 배치된 배열을 순회하게 되므로, CPU는 다음에 필요한 데이터를 미리 L1/L2 캐시에 올려놓을 수 있습니다(Prefetching). 또한 이러한 데이터 배열은 SIMD(Single Instruction Multiple Data) 명령어 처리에 완벽하게 부합하여, 한 번의 연산으로 여러 엔티티의 위치를 동시에 계산할 수 있습니다.

렌더링 파이프라인: ISM/HISM과의 결합

수만 개의 엔티티 위치를 아무리 빨리 계산해도 이를 렌더링하지 못하면 소용이 없습니다. 매스 엔티티는 언리얼의 인스턴스드 스태틱 메시(Instanced Static Mesh, ISM) 및 계층형 인스턴스드 스태틱 메시(HISM) 렌더링 시스템과 긴밀하게 통합되어 있습니다.

매스의 렌더링 프로세서는 각 엔티티의 트랜스폼 데이터를 모아 ISMC/HISMC의 인스턴스 버퍼로 한 번에 복사합니다. 이를 통해 수만 명의 군중이 단 몇 번의 드로우 콜(Draw Call)만으로 화면에 그려집니다. UE5.1 부터는 매스와 버추얼 텍스처 애니메이션(VAT)을 결합하거나 매스 크라우드 애니메이션(Mass Crowd Animation) 플러그인을 사용하여 버텍스 셰이더 기반의 초고속 애니메이션 처리까지 지원하고 있습니다.

실무 적용 사례와 StateTree 연동

에픽게임즈가 선보인 '매트릭스 어웨이큰스(The Matrix Awakens)' 데모에서 도시를 돌아다니는 수만 대의 차량과 보행자가 바로 이 매스 엔티티로 구현되었습니다. 복잡한 AI 로직의 경우, 거대한 Behavior Tree 대신 가볍고 데이터 지향적인 StateTree와 연동하여 상태 머신(State Machine) 기반의 의사결정을 수행합니다.

매스 엔티티는 아직 C++ 비중이 높고 학습 곡선이 가파르지만, 기존 방식으로는 절대 불가능한 규모의 시뮬레이션을 구현할 수 있게 해주는 마법 같은 도구입니다.

Implementation C++ / UE5
// 매스 프래그먼트 정의 (순수 데이터)
USTRUCT()
struct FMassVelocityFragment : public FMassFragment
{
    GENERATED_BODY()
    FVector Velocity = FVector::ZeroVector;
};

// 매스 프로세서 정의 (로직 처리)
UCLASS()
class UMassMovementProcessor : public UMassProcessor
{
    GENERATED_BODY()
public:
    UMassMovementProcessor();
protected:
    virtual void ConfigureQueries() override;
    virtual void Execute(UMassEntitySubsystem& EntitySubsystem, FMassExecutionContext& Context) override;
private:
    FMassEntityQuery MovementQuery;
};

void UMassMovementProcessor::ConfigureQueries()
{
    // Transform과 Velocity 프래그먼트를 가진 엔티티 쿼리 설정
    MovementQuery.AddRequirement(EMassFragmentAccess::ReadWrite);
    MovementQuery.AddRequirement(EMassFragmentAccess::ReadOnly);
}
매스 엔티티는 아직 실험적 기능이지만, 퍼포먼스의 한계를 돌파하기 위한 필수적인 도구로 자리 잡을 것입니다. C++ 기반의 데이터 지향 설계에 익숙해진다면 프로젝트의 스케일을 한 차원 높일 수 있습니다.