HLOD 레이어 설계
원거리 렌더링 최적화를 위한 Hierarchical Level of Detail 시스템
HLOD 개요
대규모 월드의 원거리 렌더링 최적화
HLOD(Hierarchical Level of Detail)는 원거리 오브젝트를 단순화된 표현으로 대체하여 드로우콜을 극적으로 감소시키는 시스템입니다. World Partition과 통합되어 자동으로 HLOD 액터를 생성하고 관리합니다.
| HLOD 타입 | 설명 | 사용 사례 |
|---|---|---|
| Instancing | ISM(Instanced Static Mesh)으로 대체, 최저 LOD 사용 | 나무, 폴리지, 임포스터 |
| Merged Mesh | 다중 메시를 단일 프록시 메시로 병합 | 건물 그룹, 구조물 |
| Simplified Mesh | 병합 + 메시 단순화(폴리곤 감소) | 원거리 산, 절벽 |
Nanite 활성화된 메시는 자체 LOD 시스템이 있지만, HLOD는 여전히 드로우콜 감소에 중요합니다. HLOD로 생성된 프록시 메시에도 Nanite를 활성화할 수 있습니다.
HLOD Layer 생성
에디터에서 HLOD 레이어 구성
1. HLOD Layer Asset 생성
// Content Browser에서 생성
Content Browser > Add > Miscellaneous > HLOD Layer
// 생성된 에셋을 열어 설정 편집
2. HLOD Layer 핵심 설정
// 레이어 타입 설정
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 할당
// 액터 선택 후 Details 패널
Details > HLOD > HLOD Layer
> 드롭다운에서 HLOD Layer Asset 선택
// 또는 여러 액터 일괄 할당
Outliner에서 여러 액터 선택 > Details > HLOD Layer 설정
계층적 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
C++ HLOD API
프로그래밍을 통한 HLOD 제어
#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);
};
#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;
}
}
}
Mesh Merge 최적화 설정
HLOD 품질과 성능 밸런스
[/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
)
- bUseLandscapeCulling - 지형에 묻힌 삼각형 자동 제거
- bMergeEquivalentMaterials - 유사 머티리얼을 하나로 병합
- GutterSize - UV 아틀라스 경계 여백, 텍스처 블리딩 방지
- bAllowDistanceField - 원거리 HLOD는 DF 비활성화로 메모리 절약
Mesh Merge 시 텍스처가 아틀라스로 병합됩니다. 너무 많은 머티리얼을 병합하면 아틀라스 해상도가 부족해질 수 있으니, 적절한 셀 크기로 HLOD 그룹을 제한하세요.
핵심 요약
- HLOD는 원거리 오브젝트의 드로우콜을 감소시키는 최적화 시스템
- 세 가지 타입: Instancing(개별 LOD), MeshMerge(병합), MeshSimplify(단순화)
- 계층적 구조로 거리별 점진적 단순화 구현
- Parent Layer로 HLOD 레이어 간 계층 관계 설정
- Nanite 통합으로 HLOD 메시에도 자동 LOD 적용 가능
도전 과제
배운 내용을 직접 실습해보세요
World Partition 레벨에서 HLOD Layer를 생성하고, 건물/나무 등 원거리 오브젝트에 적용하세요. HLOD Builder에서 Merged Mesh와 Simplified Mesh 옵션을 비교하세요.
HLOD 전환 거리(Transition Distance)를 조정하여, RPG 오픈월드에서 원거리 랜드마크가 자연스럽게 HLOD로 전환되도록 설정하세요. 시각적 팝인을 최소화하는 최적 설정을 찾으세요.
근거리(Full Mesh), 중거리(Simplified), 원거리(Imposter/Billboard)의 3단계 HLOD 레이어를 구성하세요. 각 레이어의 메모리 사용량과 시각 품질을 프로파일링하고, 대규모 오픈월드에 적합한 HLOD 전략을 수립하세요.