애니메이션 LOD와 Update Rate
Anim LOD, Update Rate Optimization (URO), SignificanceManager, Visibility 기반 최적화를 분석합니다.
애니메이션 LOD 시스템
거리/화면 크기에 따른 애니메이션 품질 단계적 축소
애니메이션 LOD는 메시 LOD와 연동하여, 먼 거리의 캐릭터는 적은 본으로 평가하거나 애니메이션 업데이트를 줄여 CPU 비용을 절감하는 시스템입니다.
| LOD 설정 | 설명 | 위치 |
|---|---|---|
| BonesToRemove | LOD별 제거할 본 목록 | USkeletalMesh LOD Settings |
| RequiredBones | LOD별 필수 본 인덱스 배열 | FSkeletalMeshLODRenderData |
| ScreenSize | LOD 전환 화면 크기 비율 | FSkeletalMeshLODInfo |
Update Rate Optimization (URO)
애니메이션 업데이트 빈도를 동적으로 조절하는 URO 시스템
URO (Update Rate Optimization)는 화면 크기, 거리, 가시성에 따라 애니메이션 업데이트 빈도를 줄이는 최적화입니다. 먼 캐릭터는 매 프레임 대신 2~8프레임마다 업데이트하여 CPU를 절감합니다.
// URO 설정
void AMyCharacter::SetupURO()
{
USkeletalMeshComponent* Mesh = GetMesh();
// URO 활성화
Mesh->bEnableUpdateRateOptimizations = true;
// 보간 활성화 (업데이트 스킵 프레임에서 보간)
Mesh->bDisplayDebugUpdateRateOptimizations = false;
// AnimUpdateRateTick 설정
// 자동으로 ScreenSize 기반 업데이트 레이트 결정
}
// 콘솔 변수로 전역 설정
// a.URO.Enable 1
// a.URO.ForceAnimRate 0 (0=자동, N=N프레임마다)
// a.URO.DrawDebug 1 (디버그 시각화)
// 프로젝트 설정에서 URO 임계값 조정
// Engine → Animation → Update Rate Optimizations
// MaxEvalRateForInterpolation: 4
// BaseNonRenderedUpdateRate: 4
// BaseVisibleDistanceFactorThresholds: [0.4, 0.2, 0.1]
URO가 프레임을 스킵할 때, 보간 없이는 캐릭터가 뚝뚝 끊기는 것처럼 보입니다. bInterpolateSkippedFrames를 활성화하면 스킵된 프레임에서 이전/다음 포즈 사이를 보간하여 시각적 끊김을 줄입니다. 다만 보간 자체에도 약간의 비용이 있으므로, 매우 먼 거리에서는 보간도 비활성화하는 것이 효율적입니다.
SignificanceManager
중요도 기반 애니메이션 리소스 할당 시스템
SignificanceManager는 각 액터/컴포넌트의 "중요도(Significance)"를 실시간으로 평가하여, 중요도가 높은 객체에 더 많은 리소스를 할당하는 시스템입니다.
// SignificanceManager 연동
class AMyCharacter : public ACharacter
{
virtual void BeginPlay() override
{
Super::BeginPlay();
// SignificanceManager에 등록
USignificanceManager* SigMgr =
FModuleManager::Get().GetModulePtr<USignificanceManager>("SignificanceManager");
if (SigMgr)
{
SigMgr->RegisterObject(
this,
FName("Character"),
// 중요도 계산 함수
[](USignificanceManager::FManagedObjectInfo* Info, const FTransform& ViewPoint)
-> float
{
AActor* Actor = Cast<AActor>(Info->GetObject());
float Distance = FVector::Dist(Actor->GetActorLocation(),
ViewPoint.GetLocation());
// 거리 기반 중요도 (0~1)
return FMath::Clamp(1.0f - (Distance / 10000.f), 0.f, 1.f);
},
// Post 중요도 처리
USignificanceManager::EPostSignificanceType::Sequential
);
}
}
// Significance 결과에 따른 애니메이션 품질 조정
void OnSignificanceChanged(float NewSignificance)
{
if (NewSignificance > 0.7f)
{
// 고품질: 풀 애니메이션
GetMesh()->SetComponentTickInterval(0.f);
EnableIK(true);
}
else if (NewSignificance > 0.3f)
{
// 중간: URO + IK 간소화
GetMesh()->SetComponentTickInterval(0.033f); // 30fps
EnableIK(false);
}
else
{
// 저품질: 최소 업데이트
GetMesh()->SetComponentTickInterval(0.1f); // 10fps
}
}
};
가시성 기반 최적화
화면 밖 캐릭터의 애니메이션 처리 전략
VisibilityBasedAnimTickOption
AlwaysTickPoseAndRefreshBones: 항상 업데이트. AlwaysTickPose: 포즈만 업데이트. OnlyTickPoseWhenRendered: 화면에 보일 때만 업데이트.
Occlusion Culling
다른 오브젝트에 가려진 캐릭터는 렌더링과 애니메이션을 모두 스킵합니다. 하드웨어 오클루전 쿼리 기반입니다.
Pause Anim When Not Visible
보이지 않을 때 애니메이션을 완전히 일시정지합니다. 다시 보이면 현재 시간에 맞춰 점프하여 재생합니다.
Reduced Bone Pool
화면 밖에서는 게임플레이에 필요한 최소 본(루트, 소켓 본)만 업데이트하여 사운드, AI 등에 활용합니다.
핵심 요약
- 애니메이션 LOD는 거리에 따라 본 수, 업데이트 빈도, IK/물리 활성화를 단계적으로 축소한다.
- URO는 화면 크기 기반으로 업데이트 빈도를 자동 조절하며, 보간으로 시각적 끊김을 줄인다.
- SignificanceManager로 중요도를 실시간 평가하여, 중요한 캐릭터에 더 많은 애니메이션 리소스를 할당한다.
- VisibilityBasedAnimTickOption으로 화면 밖 캐릭터의 애니메이션을 일시정지하여 대폭 절감할 수 있다.
- URO(60%) + 본 축소(40%) + 화면 밖 스킵(80%)을 조합하면 대규모 캐릭터 환경에서 실질적인 최적화를 달성한다.
도전 과제
배운 내용을 직접 실습해보세요
AnimBP의 LOD Threshold 설정에서 LOD별로 사용할 AnimGraph 브랜치를 분리하세요. LOD 0에서는 Full Body IK + Blend Space, LOD 2에서는 단순 State Machine만 사용하도록 구성하고, LOD 전환 시 시각적 차이를 확인하세요.
SkeletalMeshComponent의 AnimUpdateRateParams를 설정하세요. 카메라와의 거리에 따라 Tick Rate를 조절하고(가까이: 매 프레임, 중간: 2프레임마다, 멀리: 4프레임마다), 보간을 활성화하여 낮은 업데이트 레이트에서도 부드러워 보이도록 하세요.
100개의 NPC가 있는 씬에서 SignificanceManager를 활용한 종합 최적화를 구현하세요. 중요도에 따라 Tick 비활성화, LOD 강제, 본 제거를 적용하고, stat anim 명령으로 최적화 전후의 애니메이션 비용을 정량적으로 비교하세요.