PART 3 - 강의 4/7

HLOD 레이어 설계

원거리 렌더링 최적화를 위한 Hierarchical Level of Detail 시스템

01

HLOD 개요

대규모 월드의 원거리 렌더링 최적화

HLOD(Hierarchical Level of Detail)는 원거리 오브젝트를 단순화된 표현으로 대체하여 드로우콜을 극적으로 감소시키는 시스템입니다. World Partition과 통합되어 자동으로 HLOD 액터를 생성하고 관리합니다.

HLOD 타입 설명 사용 사례
Instancing ISM(Instanced Static Mesh)으로 대체, 최저 LOD 사용 나무, 폴리지, 임포스터
Merged Mesh 다중 메시를 단일 프록시 메시로 병합 건물 그룹, 구조물
Simplified Mesh 병합 + 메시 단순화(폴리곤 감소) 원거리 산, 절벽
Nanite와의 시너지

Nanite 활성화된 메시는 자체 LOD 시스템이 있지만, HLOD는 여전히 드로우콜 감소에 중요합니다. HLOD로 생성된 프록시 메시에도 Nanite를 활성화할 수 있습니다.

02

HLOD Layer 생성

에디터에서 HLOD 레이어 구성

1. HLOD Layer Asset 생성

Editor // Content Browser에서 생성 Content Browser > Add > Miscellaneous > HLOD Layer // 생성된 에셋을 열어 설정 편집

2. HLOD Layer 핵심 설정

HLOD Layer Settings // 레이어 타입 설정 Layer Type: MeshMerge // Instancing, MeshMerge, MeshSimplify 등 // 런타임 그리드 설정 Cell Size: 12800 // HLOD 셀 크기 (cm) Loading Range: 51200 // HLOD 로딩 거리 // 부모 레이어 (계층 구조) Parent Layer: (상위 HLOD Layer) // Mesh Merge 설정 bUseNanite: true // Nanite 활성화된 HLOD 메시 생성 bMergeNaniteMeshes: true bGenerateLightmapUVs: false // HLOD는 일반적으로 라이트맵 불필요

3. 액터에 HLOD Layer 할당

Editor // 액터 선택 후 Details 패널 Details > HLOD > HLOD Layer > 드롭다운에서 HLOD Layer Asset 선택 // 또는 여러 액터 일괄 할당 Outliner에서 여러 액터 선택 > Details > HLOD Layer 설정
03

계층적 HLOD 구조

거리별 다중 HLOD 레이어 구성

대규모 월드에서는 계층적 HLOD 구조를 통해 거리에 따라 점진적으로 단순화된 표현을 사용합니다.

HLOD0 (근거리)

로딩 범위: ~25,600cm
타입: Instancing
높은 품질, 개별 LOD

HLOD1 (중거리)

로딩 범위: ~51,200cm
타입: MeshMerge
건물 그룹 병합

HLOD2 (원거리)

로딩 범위: ~102,400cm
타입: MeshSimplify
블록 단위 단순화

HLOD3 (초원거리)

로딩 범위: ~204,800cm
타입: MeshSimplify
실루엣 수준 단순화

계층 구조 설정 // HLOD Layer 계층 구조 HLOD_Layer_0 (근거리) ├─ Layer Type: Instancing ├─ Cell Size: 12800 ├─ Loading Range: 25600 └─ Parent Layer: None HLOD_Layer_1 (중거리) ├─ Layer Type: MeshMerge ├─ Cell Size: 25600 ├─ Loading Range: 51200 └─ Parent Layer: HLOD_Layer_0 HLOD_Layer_2 (원거리) ├─ Layer Type: MeshSimplify ├─ Cell Size: 51200 ├─ Loading Range: 102400 └─ Parent Layer: HLOD_Layer_1
04

C++ HLOD API

프로그래밍을 통한 HLOD 제어

HLODHelper.h #pragma once #include "CoreMinimal.h" #include "WorldPartition/HLOD/HLODLayer.h" #include "HLODHelper.generated.h" UCLASS() class MYGAME_API UHLODHelper : public UBlueprintFunctionLibrary { GENERATED_BODY() public: // 액터에 HLOD 레이어 할당 UFUNCTION(BlueprintCallable, Category = "HLOD") static void AssignHLODLayer(AActor* Actor, UHLODLayer* HLODLayer); // 액터의 현재 HLOD 레이어 가져오기 UFUNCTION(BlueprintPure, Category = "HLOD") static UHLODLayer* GetActorHLODLayer(AActor* Actor); // HLOD 참여 여부 설정 UFUNCTION(BlueprintCallable, Category = "HLOD") static void SetHLODRelevance(AActor* Actor, bool bIsRelevant); };
HLODHelper.cpp #include "HLODHelper.h" #include "WorldPartition/HLOD/HLODActor.h" #include "Components/PrimitiveComponent.h" void UHLODHelper::AssignHLODLayer(AActor* Actor, UHLODLayer* HLODLayer) { if (!Actor || !HLODLayer) { UE_LOG(LogTemp, Warning, TEXT("Invalid Actor or HLODLayer")); return; } // 액터의 모든 PrimitiveComponent에 HLOD 레이어 설정 TArray<UPrimitiveComponent*> PrimitiveComps; Actor->GetComponents<UPrimitiveComponent>(PrimitiveComps); for (UPrimitiveComponent* Comp : PrimitiveComps) { if (Comp) { // HLOD 레이어 할당 // 에디터에서만 유효 - 런타임에서는 이미 빌드됨 #if WITH_EDITOR Comp->SetHLODLayer(HLODLayer); #endif } } } UHLODLayer* UHLODHelper::GetActorHLODLayer(AActor* Actor) { if (!Actor) return nullptr; if (UPrimitiveComponent* Comp = Actor->FindComponentByClass<UPrimitiveComponent>()) { #if WITH_EDITOR return Comp->GetHLODLayer(); #endif } return nullptr; } void UHLODHelper::SetHLODRelevance(AActor* Actor, bool bIsRelevant) { if (!Actor) return; TArray<UPrimitiveComponent*> PrimitiveComps; Actor->GetComponents<UPrimitiveComponent>(PrimitiveComps); for (UPrimitiveComponent* Comp : PrimitiveComps) { if (Comp) { // HLOD에 포함/제외 설정 Comp->bEnableAutoLODGeneration = bIsRelevant; } } }
05

Mesh Merge 최적화 설정

HLOD 품질과 성능 밸런스

DefaultEngine.ini [/Script/Engine.HLODSettings] ; Mesh Merge 설정 +HLODLayerSettings=( LayerType=MeshMerge, MeshMergeSettings=( bUseLandscapeCulling=true, ; 랜드스케이프에 가려진 삼각형 제거 bMergeEquivalentMaterials=true, ; 동일 머티리얼 병합 bGenerateNaniteEnabledMesh=true, ; Nanite 활성화 bAllowDistanceField=false, ; 원거리용이므로 DF 불필요 GutterSize=4, ; 텍스처 아티팩트 방지 LODSelectionType=AllLODs ; 모든 LOD 사용 ), RuntimeGrid="DistantGrid", LoadingRange=204800.0 )
Mesh Merge 최적화 팁
  • bUseLandscapeCulling - 지형에 묻힌 삼각형 자동 제거
  • bMergeEquivalentMaterials - 유사 머티리얼을 하나로 병합
  • GutterSize - UV 아틀라스 경계 여백, 텍스처 블리딩 방지
  • bAllowDistanceField - 원거리 HLOD는 DF 비활성화로 메모리 절약
텍스처 아틀라스 크기

Mesh Merge 시 텍스처가 아틀라스로 병합됩니다. 너무 많은 머티리얼을 병합하면 아틀라스 해상도가 부족해질 수 있으니, 적절한 셀 크기로 HLOD 그룹을 제한하세요.

SUMMARY

핵심 요약

  • HLOD는 원거리 오브젝트의 드로우콜을 감소시키는 최적화 시스템
  • 세 가지 타입: Instancing(개별 LOD), MeshMerge(병합), MeshSimplify(단순화)
  • 계층적 구조로 거리별 점진적 단순화 구현
  • Parent Layer로 HLOD 레이어 간 계층 관계 설정
  • Nanite 통합으로 HLOD 메시에도 자동 LOD 적용 가능
PRACTICE

도전 과제

배운 내용을 직접 실습해보세요

실습 1: HLOD 레이어 기본 설정

World Partition 레벨에서 HLOD Layer를 생성하고, 건물/나무 등 원거리 오브젝트에 적용하세요. HLOD Builder에서 Merged Mesh와 Simplified Mesh 옵션을 비교하세요.

실습 2: HLOD 거리 및 품질 조정

HLOD 전환 거리(Transition Distance)를 조정하여, RPG 오픈월드에서 원거리 랜드마크가 자연스럽게 HLOD로 전환되도록 설정하세요. 시각적 팝인을 최소화하는 최적 설정을 찾으세요.

심화 과제: 다중 HLOD 레이어 전략

근거리(Full Mesh), 중거리(Simplified), 원거리(Imposter/Billboard)의 3단계 HLOD 레이어를 구성하세요. 각 레이어의 메모리 사용량과 시각 품질을 프로파일링하고, 대규모 오픈월드에 적합한 HLOD 전략을 수립하세요.