역자의 말.
요즘은 Devops 와 엔진 렌더링 부분 커스터마이징을 주력으로 작업하고 있지만 곧 다가올 패키징과 로딩 레벨의 최적화 분야도 언젠가는 작업을 해야하기 때문에 데이터 스트리밍이나 월드 파티션과 관련 된 모든 부분을 지속적으로 학습중입니다. 중국에서 오랫동안 Zhihu 에서 활동 하다보니 중국어 테크 블로거들 자료들을 자주 보게 됩니다. 그 중 하나를 발췌 하여 번역 해 봤습니다. 기계번역을 사용한 페이지 번역으로 중국어 페이지를 보면 어색한 말이나 말이 안되는 것들이 많은데요... 중국 엔지니어들이 사용하는 특정 단어들이 중국어 영어 한국어 번역으로 브릿지 번역을 하더라도 애초에 중국인들 개념으로 사용하는 중국어 단어나 비유등이 있고 젊은 엔지니어들은 인터넷 용어(중국에서 하루에도 정말 많은 인터넷 용어와 축약어가 많이 창조 되거든요.)를 섞어 사용할 경우 정말 번역결과가 산으로 가기도 하고... 암튼... 저도 기술의 도움을 받아서 초안을 번역하고 제가 다 트리트먼트 한 내용이라서 조금 더 편히 보실 수 있을겁니다.
월드 파티셔닝은 UE5가 대규모 월드 프로젝트에 제공하는 새로운 솔루션 세트입니다. UE4의 월드 컴포지션에 비해 개선된 점이 매우 많습니다. 공식 웹사이트에도 매우 구체적인 소개가 나와 있습니다.
어쨌든 이 기능은 오래전에 나온 기능이고, 월드 파티션에 대한 기본 튜토리얼은 어디에서나 많이 찾아볼 수 있기 때문에 기본적인 사용법에 대해서는 자세히 설명하지 않겠습니다.
제 경험에 비추어 볼 때 과거의 월드 콤포지션 솔루션과 비교했을 때 가장 가치 있는 부분은 씬 공간 분할, 스트리밍, OFPA 스토리지, 데이터 레이어, 레벨 인스턴스, HLOD, 월드 파티션 빌더 및 콘텐츠 번들이라고 생각합니다. 이러한 부분에 대한 몇 가지 코드 읽기 노트와 인사이트를 소개합니다.
씬 공간 분할
공간 분할은 주로 장면을 더 효율적인 방식으로 분할하는 방법에 관한 것입니다.
씬의 공간 분할이 없는 경우, 플레이어와 가장 가까운 100미터에 있는 액터를 모두 가져오는 것과 같은 씬과 관련된 일부 요구 사항을 수행하려면 씬의 모든 액터를 트래버스하여 플레이어와의 거리를 차례로 비교하고 100미터에 있는 액터를 필터링하면 됩니다.
씬의 액터 수가 매우 많으면 이 트래버스 작업에 많은 시간이 소요됩니다.
씬으로 이동하여 그리드를 그리면 100 미터마다 그리드가 그리드이고,이 모든 액터가 요구하는 플레이어에서 가장 가까운 100 미터를 검색 할 때 먼저 어떤 그리드에있는 플레이어를 찾은 다음 그리드 근처의 플레이어를 찾아 모든 액터를 꺼내서 거리를 차례로 판단 할 수 있으므로 모든 액터를 씬을 횡단 할 필요가 없으므로 계산량을 줄이고 성능을 향상시킬 수 있습니다. 월드파티션이 만든 씬 공간 분할은 엔진에서 “계층적 해시 격자(Hierarchical Hash Grid)”라고하는 일종의 그리드 드로우 방법이기도합니다.
트래버스 : 사전적인 의미로 보면 횡단의 뜻 이지만 렌드스케이프라는 특성을 감안하여 이해하자면 지질학적 측면에서의 트래버스 즉 어느 한쪽에서 다른 한쪽까지를 탐색 또는 조사 하는 일련의 행위로서 그 의미를 이해할 수 있겠다.
이 격자(Grid) 그리기 알고리즘과 기존의 격자 그리기 방법의 차이점은 무엇인가요? 아니면 기존의 격자 그리기 방식에 비해 개선된 점은 무엇인가요? 계층적 해시 격자(Hierarchical Hash Grid)라고 불리기 때문에 개선점은 실제로 계층과 해시라는 두 가지 키워드와 관련이 있습니다. 기존의 그리드 드로우 방식에는 다음과 같은 두 가지 주요 문제가 있습니다:
- 비어 있는 격자(Grid)많을경우 이러한 빈 격자(Grid)를 저장하면 필연적으로 메모리가 낭비될 수밖에 없습니다. 예를 들어 10*10 격자(Grid)에 대한 2차원 배열을 생성하는 경우, 액터가 있는 격자(Grid)수가 적을 수 있으므로 이 2차원 배열에서 많은 메모리가 낭비됩니다.
- 일부 액터의 바운드가 매우 커서 여러 격자(Grid)에 걸쳐 있는 경우 이 액터는 어느 격자(Grid)에 속할까요?
따라서 “계층적 해시 격자(Hierarchical Hash Grid)” 는 이 두 지점에 대한 격자(Grid)를 그리는 개선된 방식을 제공합니다. 많은 수의 격자(Grid)가 비어 있으므로 빈 격자(Grid)를 위한 공간을 저장하는 데 신경 쓰지 않아도 됩니다.
TArray와 TSet의 차이에 비유할 수 있는데, 1차원의 경우 그리드 x 좌표를 저장할 때 0~100은 엘리먼트 0, 101~200 좌표는 엘리먼트 1에 저장하면 액터의 전체 씬을 지정된 하나의 격자(Grid)에 넣을 수 있습니다.
하지만 전체 1차원 씬의 액터 좌표 분포가 균일하지 않으면 빈 격자(Grid)가 많아지고, 빈 배열 요소의 메모리가 낭비됩니다.
TSet을 사용하여 숫자에 해당하는 해시 값에 따라 내부적으로 인덱싱되는 격자(Grid)를 저장하면 이러한 빈 격자(Grid)는 실제 메모리를 할당하지 않으므로 많은 공간을 절약할 수 있습니다.
그런 다음 이 접근 방식을 평면과 공간으로 확장하여 격자 그리드(x,y 또는 x,y,z 방향으로 번호 매기기)에 대한 해시를 생성하고 이를 TSet에 저장하면 2D 배열에 비해 많은 공간을 절약할 수 있으므로 위에서 언급한 첫 번째 문제를 해결할 수 있습니다.
일부 액터의 바운드(Bound)가 특히 큰 경우, 작은 격자 위에 더 큰 범위의 격자를 만들 수 있습니다. 예를 들어 100미터 격자가 있는데 액터를 맞출 수 없다면 200미터 격자를 만들어서 맞추고, 그래도 안 맞으면 400미터 격자를 만들어서 맞추는 식으로 전체 맵과 크기가 같은 마지막 격자에 액터를 맞출 수 있을 때까지 시도할 수 있습니다.
이러한 접근 방식을 계층적이라고 합니다. 첫 번째 단계에서 해시를 사용하여 격자를 저장했기 때문에 해시 값을 확장하고 4개의 튜플(Tuple)과 같은 격자(x,y,z 방향 번호, 레벨 l)를 키로 사용하여 해시를 구축하여 전체 공간 구조를 저장할 수 있으며 마침내 위의 두 가지 문제를 해결할 수 있습니다.
월드 파티션은 내부적으로 이러한 방식으로 공간을 관리합니다. UE5 에는 월드 파티션 외에도 스마트 오브젝트, 존 그래프 등 이런 식으로 공간을 관리하는 모듈이 많이 있습니다. 특히 HierarchicalGrid2D.h를 볼 수 있는데, 이는 일반 컨테이너로 프로젝트를 직접 재사용할 수도 있습니다. 그리고 “월드파티션 런타임 스페이셜 해시”의 월드파티션 구현은 아래 그림과 같이 WorldPartitionRuntimeSpatialHash.h의 FSpatialHashStreamingGridLevel에 있습니다:
LayerCellsMapping은 LayerCells 배열의 아래 첨자에 매핑된 xy의 인덱스입니다. 위에서 설명한 계층적 해시 격자(Hierarchical Hash Grid)와 본질적으로 동일합니다.
물론 계층적 해시 격자(Hierarchical Hash Grid) 접근 방식은 몇 가지 버그가 발생할 수도 있는데, x축과 y축을 덮고 있는 일부 액터는 항상 로드되고 어떤 일이 있어도 언로드되지 않습니다. 위의 알고리즘에 따르면 그리드를 그릴 때 월드파티션이 축 정렬을 하기 때문에 축을 덮고 있는 액터를 제대로 된 그리드에 넣을 수 없어 결국 전체 씬만큼 큰 가장 큰 그리드에 넣게 되고, 이 가장 큰 그리드는 당연히 플레이어의 위치를 덮고 있는 그리드이므로 이러한 액터는 절대 언로드되지 않는다는 것을 쉽게 이해할 수 있으며, 아래 5.3에 이에 대한 글이 있습니다. 솔루션의 하위 버전은 이 원칙에 따라 수동으로 변경할 수 있습니다.
게임에서 Preview Grids를 클릭하면 현재 로딩 그리드를 볼 수 있으며, 다음 셀 크기를 조정할 수 있습니다. 레벨 0 그리드 크기, 레벨 1 그리드는 기본값인 0 그리드 2배, 아래 그림에서 현재 로딩 그리드를 볼 수 있습니다. 로딩 범위는 로딩 거리, 즉 그림에서 원의 반경이며, 그리드가 스윕된 것은 는 로딩 상태입니다.
Use Aligned Grid Levels 이것은 비활성(Disabled)화되어야합니다. 위의 두 그래프에서도 볼 수 있듯이 두 레벨의 그리드 경계가 정렬되지 않았으며 활성화 된 경우 다중 레이어 그리드 좌표가 경계에 따라 엄격하게 정렬되는 것을 볼 수 있습니다.
격자의 각 레벨이 정렬되면 좌표축을 덮고있는 액터가 제거되지 않기 때문에 비활성화 하면 이 문제를 해결할 수 있습니다.
스트리밍 생성
5.3 코드를 살펴보고 있는데, 이전 버전은 흐름은 비슷하지만 누락된 기능이 꽤 있습니다. 월드파티션의 진입점은 UWorldPartition 클래스입니다.
오브젝트 자체는 AWorldSettings에 연결되고, 구성과 런타임은 기본적으로 이 클래스에 있으며, 엔진에는 이 클래스에 대한 커스텀 에디터가 있어 WorldSettings 탭에 표시할 수 있습니다.
PIE로 게임을 시작하여 씬을 로드하면 OnBeginPlay 함수가 트리거되고, 이 함수는 결국 UWorldPartitionRuntimeSpatialHash의 GenerateStreaming 함수를 호출합니다.
이 함수는 패키지를 생성하는 곳으로, PIE 아래 /Memory부터 시작하여 패키지에 생성되며, 패킹할 때 UWorldPartition::GatherPackagesToCook을 호출하여 각 셀에 해당하는 패키지를 생성한 다음 해당 데이터를 패키지에 하나씩 저장합니다.
따라서 월드 파티션은 여전히 UE4 의 원래 levelStreaming 메커니즘을 통해 동적으로 로드 및 언로드 되고 있습니다.
쿠키의 결과는 실제로 기존 서브 레벨 패키지와 동일하지만, 이 패키지를 실제 리소스로 전환하는 프로세스는 에디터에서 매우 특수한 월드 파티션이 자동으로 수행하며, 해당 패키지의 메모리에 직접 생성된다는 점만 다릅니다.
아래에서 볼 수 있듯이 UWorldPartitionRuntimeLevelStreamingCell은 레벨 스트리밍 오브젝트를 상속하는데, 이는 ue4의 대형 맵 로딩과 동일한 메커니즘입니다.
이 단계에서 가장 중요한 것은 모든 액터에 대한 공간 분할을 하는 것으로, 각 액터는 위치와 둘러싸는 박스의 크기에 따라 실제 셀에 배치되며, 둘 이상의 액터에 참조 관계가 있는 경우 참조 관계가 있는 액터는 동일한 클러스터에 입력됩니다.
참조 관계는 다른 액터를 참조하는 것과 액터에 의해 참조되는 것을 모두 의미한다는 점에 유의해야 합니다.
일반적으로 여러 액터에 대한 레퍼런스는 데이터 레이어를 교차할 수 없으며, 그렇지 않으면 로드 시 문제가 발생할 수 있습니다. 참조가 여러 데이터 레이어에 걸쳐 있는 경우 맵이 열릴 때 MapCheck 오류가 보고되며, 해당 액터가 데이터 레이어와 함께 로드되지 않고 해당 셀이 로드되는 즉시 바로 로드될 가능성이 매우 높습니다.
그 이유는 월드파티션의 로직이 먼저 셀을 분할한 다음 셀의 모든 액터가 어느 데이터 레이어에 속하는지 살펴본 다음 클러스터가 어느 셀에 속할지 결정하기 때문입니다.
이 파일은 월드파티션의 버그와 다양한 로딩 문제를 검사하는 데도 유용합니다. 엔진 5.3 버전에서는 wp.Editor.DumpStreamingGenerationLog를 사용하여 결과를 한 번 출력할 수도 있는데, 이 명령은 실행하지 않고도 결과를 출력할 수 있습니다.
다음은 Lyra의 레벨(Map) 중 하나에 대한 정보입니다.
이전 단락에서는 현재 맵 내 모든 액터의 ActorDesc 정보가 기록됩니다.
그런 다음 클러스터의 그룹화 정보가 있는데, 어떤 액터가 함께 그룹화되었는지 확인하는 데 중요합니다.
그 다음 블록 정보, 위에 있는 이것은 Persistent Level, 즉 맵 레벨이 작동하면 들어오며 영원히 제거되지 않는 Actor입니다.
맵 청크의 통계, 정확히 몇 개의 레벨로 나뉘었는지, 각 레벨에 몇 개의 셀이 있는지, 각 셀에 몇 개의 액터가 있는지 등을 확인할 수 있습니다.
그리고 각 그리드, 각 셀에 대한 패킷 정보입니다.위의 사진은 MainGrid, L0_X0_Y-1이라는 Cell의 Actor 정보를 볼 수 있습니다.앞에서 구체적으로 HashGrid의 key인 L0_X0_Y-1에 대해 언급했는데, L0은 가장 작은 1차 플롯이고 L1의 크기는 L0의 2배입니다.그리고 X0_Y-1은 xy 좌표의 번호입니다.
Runtime 타입의 DataLayer가 있다면 생성할 때 이러한 Cell을 보게 되는데, Cell의 번호 외에 DL로 시작하는 단락이 있습니다.이것은 이 셀 안에 DataLayer가 있다는 것을 의미합니다.
그러므로 동일한 셀도 DataLayer에 따라 분할됩니다. 따라서 이것은 위의 문제를 설명하는데, 왜 한 Actor가 다른 DataLayer의 Actor를 인용하면 이 Cluster가 어디에 있는지 알 수 없게 되는지를 설명합니다.
왜냐하면 클러스터는 무조건 셀 밑에 있어야 하기 때문입니다.
UpdateStreamingState
런타임에 UWorldPartitionSubsystem::UpdateStreamingState() 함수는 매 프레임마다 호출되며, 내부적으로 현재 스트리밍 소스에 따라 로드 및 언로드해야 할 패킷을 업데이트합니다.
각 월드파티션에 대해서도 UWorldPartitionStreamingPolicy::UpdateStreamingState() 함수가 호출됩니다.
알고리즘은 매우 간단합니다.
실제로 측정할 소스를 기반으로 거리를 계산하고, 어떤 셀을 ToLoad 및 ToActivate해야 하는지 확인한 다음, 이전 프레임에서 셀을 로드하고 활성화하여 차이를 계산하고, 차이의 결과로 이 프레임에서 셀 목록을 로드하고 활성화해야 한다는 것을 알 수 있습니다.
이전 프레임에 Load가 있었고 이 프레임에서 Load 및 Activate가 필요한 셀 목록이 차이의 결과이며, 이전 프레임에 Load가 있었던 셀 목록과 이 프레임에서 ToLoad/ToActivate가 있었던 셀 목록을 사용하여 차이점을 수행하면 차이의 결과는 이 프레임에서 UnLoad가 필요한 셀 목록이 됩니다.
Load 및 Activate는 이전 레벨 스트리밍과 동일한 작업을 수행하며, Load는 리소스를 로드하고 Activate는 맵을 표시하고 AddToWorld를 활성화합니다.
OFPA(One File Per Actor)
액터의 기본 구현 파일은 사실 액터의 SetPackageExternal(true) 를 호출하여 설정하는 것으로, 내부에서 이 액터 패키지와 독립된 파일을 생성하고, 원본 오브젝트의 플래그에 RF_HasExternalPackage 로 표시합니다.
이 독립된 패키지는 "Content/ExternalActors/" 폴더에 저장되며, 액터가 폴더에 저장되면 폴더 자체의 오브젝트도 "Content/ExternalObjects" 폴더에 존재할 것입니다.
이 두 폴더는 엔진의 콘텐츠 브라우저에 표시되지 않습니다.
특정 저장 및 읽기를 처리하는 전용 클래스 FExternalPackageHelper가 있습니다.
해당 폴더는 결국 액터인지 여부에 따라 선택됩니다.
각 액터에 대해 월드파티션 아래에 FWorldPartitionActorDesc 가 추가로 생성되며, 여기에는 자체 Guid, 이름, 경로, 베이스 클래스, 네이티브 베이스 클래스, 다른 액터의 레퍼런스, 그것이 속한 데이터 레이어 등 월드파티션와 관련된 현재 액터에 대한 기본 정보가 들어 있습니다.
데이터 레이어 등 월드파티션이 클러스터를 구축할 때 의존하는 것은 바로 이 참조와 해당 데이터 레이어의 정보입니다.
구체적으로 A가 B를 참조한 다음 이 단방향 관계를 양방향으로 전환하여 연결된 그래프를 그린 다음 연결된 모든 그래프가 클러스터이고 마지막으로 클러스터의 목록이 됩니다.
구체적으로 다음 함수 알고리즘을 참조할 수 있습니다.
Data Layer
데이터 레이어는 사실 ue4의 레이어 기능을 대체하는 것으로, 데이터 레이어 아래에 액터를 일괄적으로 배치하여 런타임에 프로그램을 동적으로 로드할 수 있습니다.
하지만 ue4의 레이어와 달리 액터는 여러 데이터 레이어에 속할 수 있습니다.
여기서 에디터와 런타임 유형을 구분하는 것이 중요합니다. 런타임인 경우 추가 런타임 상태가 필요합니다.
DataLayerManager의 다음 함수를 사용하면 런타임에 로드 및 언로드를 제어할 수 있습니다.
데이터 레이어의 상태를 수신하는 델리게이트도 있습니다. 이 모든 함수는 블루프린트에서 호출할 수 있습니다.
Level Instance
이는 ue5의 새로운 메커니즘으로, 유니티의 프리팹과 다소 유사합니다(문서를 참조하세요):
이 자체는 사용하기가 꽤 간단합니다.LevelInstance를 사용하기에 가장 좋은 장소는 지도에 있는 관심사로, 만약 같은 관심사가 여러 개 있고 내용이 비슷하다면 LevelInstance로 만들어서 이 LevelInstance를 지도 곳곳에 배치해서 재사용할 수 있다고 생각합니다.
동적 게이트웨이를 실현하고 다른 시간에 다른 레벨 인스턴스를 로드하는 데 사용할 수도 있습니다.
또 다른 중요한 기능은 레벨 인스턴스를 사용하여 게이트웨이를 설계할 수 있다는 것입니다.ue4에 있을 때, 각 하위 게이트웨이는 자신만의 BP를 가질 수 있지만, ue5의 WorldPartition은 모두 하나의 큰 게이트웨이라면, 정상적인 상황에서는 하나의 게이트웨이의 BP만 있을 뿐, 이는 기획에 있어 매우 구질구질한 것입니다.
하지만 다른 관심사에 대해 해당 액터를 하나의 레벨 인스탕스에 포함시키면 이 레벨 인스탕스에 이 흥미점만의 BP를 쓸 수 있습니다.
또 다른 한 가지는 이론적으로 월드 파티션에 대해 스태틱 베이킹을 할 수 있는데, 레벨 인스턴스 자체는 일반 레벨이므로 빌드 데이터를 별도로 베이킹할 수 있으며, 월드 파티션에 베이크된 빌드 데이터로 여러 레벨 인스턴스를 패킹하면 다음과 같이 할 수 있다는 점입니다.
월드 파티션이 다중 정적 베이크를 지원하나요? 그러나 나는 이것을 시도하지 않았기 때문에 내가 옳은지 확신 할 수 없으므로 이것을 해본 사람이 좀 더 분명할 수 있을 것입니다.
클래스의 더 나은 사용법은 APackedLevelActor이며,이 클래스는 내부의 모든 내부 액터를 다른 메시 인스턴스에 따라 자동으로 허용하고, 내부의 큰 맵의 월드 파티션으로 스윙하면 배치 후 액터의 조합이며, 레벨 인스턴스를 직접 열면 액터의 배치 전의 조합이지만 해당 수준의 블루프린트가 있기 때문에이 수준의 블루프린트는 도구의 공식 수동 배치에 해당하는 배치의 세부 사항으로 제어 할 수 있으므로 사용하기에 매우 좋습니다.
마지막으로 Level Instance 스토리지에 대해 말씀드리겠습니다.
LevelInstance 자체가 하나의 level이기 때문에 하나의 umap자원으로 따로 저장한 것인데, 이 level이 CDO이고 unity에서의 prefab 그 자체라고 보시면 됩니다.
LevelInstance를 게이트웨이에 끌어다 놓으면 내부의 Actor가 ExternalPackage를 추가로 생성합니다. 즉, __ExternalActor__경로 아래에 LevelInstance의 각 Actor 리소스가 있습니다.umap과 WorldPartition 내부의 이러한 단일 Actor 파일은 CDO와 인스턴스 개체 간의 관계로 이해될 수 있는데, 동일한 Level Instance가 여러 인스턴스 개체에 해당하기 때문입니다.
HLOD
HLOD 공식 문서를 볼 수 있습니다.
여러 레벨의 HLOD를 가질 수 있으며, 각 레벨에는 개별 베이킹, 인스턴스 결합, 메시 결합, 메시 결합을 위한 면 축소 등의 옵션이 있습니다.
한 가지 유의할 점은 HLOD는 자체 내부 셀이 있는 자체 추가 그리드를 생성하며, 이 그리드는 메인 그리드에 배치되지 않고 월드 세팅 규칙의 영향을 받지 않고 HLOD 레이어 구성 파일의 영향을 받는다는 점입니다. 그런 다음 HLOD는 WorldPartitionBuilder를 통해 구현됩니다.
WorldPartitionBuilder
이것은 사실 에디터 Commandlet 스크립트입니다. 에디터 레벨에서 월드 파티션은 액터별 OFPA이고, 패키징된 것은 ue4의 자체 맵과 구분할 수 없기 때문입니다. 실제 게시된 맵을 생성하기 위해 에디터 맵에서 쿠키 작업을 수행하는 것과 같습니다. 따라서 월드파티션은 프로그래머가 일부 작업을 사용자 정의하고 편집기 맵에서 사용자 정의 처리를 수행한 다음 결과를 유지할 수 있는 도구를 제공합니다.
여기에는 다음과 같은 기능이 포함되어 있습니다. HLOD 베이크, 미니맵 베이크, 식생 베이크, RVT 베이크 등.
스마트 오브젝트를 비롯한 일부 플러그인에는 전체 맵의 스마트 오브젝트를 해당 컬렉션으로 일괄 수집할 수 있는 빌더도 있습니다.
물론 엔진에서 제공하는 기능 외에도 예를 들어 액터를 잘라내고 병합하거나 배치 작업을 수행하는 Builder를 사용자 지정하여 맵 성능 최적화와 관련된 일부 기능을 수행할 수 있으므로 맵 개발이 매우 편리합니다. 장면의 다양한 관심 지점을 카운팅하고 액터 유형을 지정하여 보고서로 구성하고 정적 분석을 수행하는 등의 데이터 수집 작업도 수행할 수 있습니다.
Builder를 찾아보면 오버라이드라는 몇 가지 함수만으로 원하는 것을 실현할 수 있습니다.그 중 GetLoadingMode는 Commandlet에게 해당 지역을 어떻게 처리하는지 알려줍니다.
그 중 Custom/EntireWorld는 한 번에 전체 지도를 처리할 수 있고 IterativeCells/IterativeCells2D는 Cell로 나눌 수 있으며 Cell로 나눌 경우 RunInternal 함수를 여러 번 호출합니다.
RunInternal 내부에서는 기존의 TActorIterator를 통해 현재 구획의 Actor를 통과하거나 FActorDescContainerCollection::TIterator(WorldPartition)를 통해 모든 Actor의 ActorDesc를 통과합니다.
ContentBundle
이 기능은 공식적으로 문서화되어 있지도 않아서 궁금해하는 분들도 계시겠지만, ue5의 WorldPartition에 에디터가 제공됩니다.
사실 이 기능은 GameFeature를 위한 것입니다.
게임피처는 원래 없던 많은 기능을 동적으로 게임에 추가할 수 있고 WorldPartition의 경우 ContentBundle을 통해 원래 관문에 Actor를 동적으로 추가할 수 있으므로 우리 프로젝트는 기본 맵만 만들 수 있고 동적으로 가변적인 부분은 ContentBundle을 통해 구현할 수 있습니다.
구체적으로 GameFeatureData의 구성 파일에서 새 액션을 추가하고, 이 액션은 월드 파티션 콘텐츠 추가를 선택해야 하며, 그 다음 ContentBundleDescriptor 편집으로 이동하면 됩니다.
여기에는 아무 것도 없고 이름만 있는 것을 볼 수 있으며, 이름을 원하는 이름으로 변경한 다음 저장하고 편집기를 다시 시작하면 됩니다. 그러면 ContentBundlesOutliner에서 방금 추가한 콘텐츠 번들을 볼 수 있습니다.
그런 다음 이 콘텐츠 번들 안에 액터를 넣으면 이 액터는 게임 피처의 라이프사이클을 따릅니다.
어떻게 넣을지는 현재로서는 딱히 방법이 없어서 일단 ContentBundle을 현재 편집기의 Context로 설정한 후 설정하는 수밖에 없습니다.
편집기의 컨텍스트를 설정하는 방법에 대한 자세한 설명은 다음과 같습니다.
하지만 ContentBundle은 LevelInstance를 지원하지 않으며, ue5.5 에서 이 기능이 삭제된다는 루머도 있으므로 이 기능을 자신의 프로젝트에 사용 할지, 아니면 자신의 프로젝트를 보고 실제 상황을 고려할지 결정해야 합니다.
중국어 원문.
'TECH.ART.FLOW.IO' 카테고리의 다른 글
AWS re:Invent 2021 - How Epic Games develops Fortnite faster with a build farm on AWS (0) | 2024.01.14 |
---|---|
[번역] Unreal Engine 5 Open World Production (1) | 2024.01.11 |
[주석번역] Horizon Zero Dawn:오픈 월드 QA 사례 연구 (1) | 2024.01.05 |
[주석번역]STREAMING THE WORLD OF HORIZON ZERO DAWN (3) | 2024.01.02 |
[주석번역,해석]수백만 개의 자산을 위한 확장 도구 (2) | 2024.01.02 |