게임엔진/ECS(Unity)

BlobAsset의 개념

tsyang 2026. 2. 7. 22:31

상황

 

ECS로 심리스 오픈월드를 구현하고싶다. 자연스럽게 지역과 지역을 넘나드려면 로딩 속도가 생명이다. 게임 데이터에는 여러가지가 있겠지만 NavMesh만 우선 생각해보자.

 

게임 속에는 공중유닛, 수영할 수 있는 유닛, 지상유닛 등으로 나뉘어져 각각 NavMesh가 필요하다.

 

NavMesh는 굉장히 간략하게 보자면 폴리곤의 집합과 인접 데이터의 모음이라 할 수 있으며 이 데이터들의 길이는 제각각이다. 그럼 이걸 어떻게 구현할 것인가?

 

 

DynamicBuffer?

public struct NavPolygonElement : IBufferElementData
{
    public int StartVertexIndex; 
    public int VertexCount;
    public int NeighborStart;    // 인접 인덱스 버퍼에서의 시작 위치
}

 

ECS에서 가변배열하면 DynamicBuffer를 떠올릴 수 있다. 그리고 실제로 DynamicBuffer로 Navmesh를 구현할 수 있다. 유닛마다 NavMesh데이터를 한 벌씩 가지는 건 말이 안되니, 맵 데이터에서 한번 DynamicBuffer로 데이터를 변환하고 유닛마다 NavMesh의 id를 통해 접근할 수 있을 것이다.

 

근데 이건 사실 좋지 않다. 우선 지역 데이터(Subscene)을 저장장치에서 메모리로 올린다. 이후 SubScene 파일에서 읽어온 데이터 스트림을 ECS 메모리 구조에 맞게 재구성 해야한다. 이 과정에서 ECS메모리 영역에 새로 힙을 할당하고 데이터를 복사하는 과정이 포함된다. 이러 다음 지역을 로드할 때 시간이 더 걸릴 뿐더러, 맵이 로드/해제 될 때 메모리 파편화가 생길 여지가 있다. 

 

또한 DynamicBuffer는 특정 엔티티에 귀속된 가변 데이터다. 따라서 기본적으로 Safety Check가 수행된다.

 

 

BlobAsset

public struct NavPolygonBlob
{
    public BlobArray<float3> Vertices;
    public BlobArray<int> NeighborIndices;
}

 

사실 필요한 데이터는 이미 Subscene이 bake될 때 다 마련됐다. 이걸 그대로 쓰면 안 될까? 라는 의문이 든다. 그렇다 Subscene이 로드될 때 그 데이터를 그대로 쓰는 게 BlobAsset이다.

 

BlobAsset은 불변(Immutable)의 바이너리 데이터 덩어리이다. SubScene이 로드될 때, 유니티는 이 데이터를 ECS의 메모리 영역에 복사하지 않고 그냥 디스크에 저장된 바이너리 상태 그대로 Native Memory 영역에 로드한다. 그리고 이것에 대한 참조 포인터를 넘겨주면 끝이다. 

public struct NavMeshInstance : IComponentData
{
    public BlobAssetReference<NavMeshBlob> BlobRef;
}

public void Execute(in NavMeshInstance instance)
{
    ref var mesh = ref instance.BlobRef.Value;
    var firstVertex = mesh.Vertices[0];
}

 

BlobAsset은 DynamicBuffer와 달리 Safety Check가 필요 없다. 

 

 

정확한 사용법은 AI한테 물어보자.

'게임엔진 > ECS(Unity)' 카테고리의 다른 글

ECS에서 Behavior Tree 구현하기 (ft. xNode)  (0) 2026.02.08
ECB + sortKey  (0) 2025.11.30
Entities - 컴포넌트 구조  (0) 2023.02.25