Unreal Engine 5.8 Lumen Reflections Bug: 소리 없는 Screen-Space Fallback 해결 방법
핵심 요약
Unreal Engine 5.8에서 Lumen GI를 비활성화할 때 Lumen Reflections가 경고 없이 SSR로 fallback되는 렌더링 버그가 발생하고 있습니다. 이 글에서는 해당 버그의 아키텍처적 원인과 함께 C++ 코드, INI 설정 파일, 그리고 엔진 소스 코드 수정을 통한 세 가지 해결 방법을 설명합니다. 또한 이러한 프레임 저하 이슈가 멀티플레이어 동기화에 미치는 영향과 함께 [horizOn](https://horizon.pm)을 통한 동적 설정 관리 방법 및 프로덕션 베스트 프랙티스를 제안합니다.
소리 없는 Fallback: UE 5.8에서 Reflections가 깨지는 이유
Unreal Engine 5.8로 업그레이드하는 것은 표준적인 Rendering Pipeline 업데이트였어야 했지만, 많은 그래픽 엔지니어들이 메탈릭 머티리얼의 반사가 밋밋하고 탁하게 변하는 현상을 겪고 있습니다. 이전 버전에서 선명한 레이트레이싱 디테일을 보여주던 표면들이, 반사되는 오브젝트가 화면에서 벗어나는 순간 흐릿한 Screen-Space Reflections (SSR)로 되돌아가 버립니다. 경고 없이 발생하는 이러한 렌더링 퀄리티 저하는 바로 unreal engine 5.8 lumen reflections bug 때문입니다. Lumen Global Illumination (GI)가 완전히 활성화되어 있지 않으면 엔진이 reflections를 제대로 렌더링하지 못하는 버그입니다. baked lighting이나 다른 GI 솔루션을 사용하는 게임의 경우, 이로 인해 막대한 GPU overhead를 감수하거나 비주얼 퀄리티를 포기해야 하는 양자택일의 상황에 직면하게 됩니다.
이 문제의 근본 원인은 Unreal Engine 5.8이 Rendering Pipeline을 초기화하는 방식에 있습니다. 이전 버전에서는 GPU 리소스를 절약하기 위해 Lumen Global Illumination은 비활성화하고, 메탈이나 유리의 고품질 스펙큘러 하이라이트를 유지하기 위해 Lumen Reflections만 활성화하는 설정이 가능했습니다. 이 standalone reflections 모드는 global indirect lighting을 라이트맵에 베이크하는 중사양 하드웨어 및 타겟 최적화 프로파일에서 매우 유용하게 쓰였습니다. 그러나 UE 5.8에서는 Lumen GI를 끄면 전체 Lumen Scene 표현(representation)까지 경고 없이 비활성화되어, 로그에 아무런 경고나 에러도 남기지 않고 reflections가 즉시 screen-space 방식으로 fallback됩니다.
이 Regression은 특히 멀티플랫폼 타이틀에 치명적입니다. 콘솔에서 안정적인 60 FPS로 구동되도록 최적화된 게임이라도, 반사 재질을 제대로 표현하기 위해 Lumen GI를 억지로 켜야 한다면 그래픽 버짓(GPU 프레임 타임)이 한계를 초과하게 됩니다. 이 fallback이 발생하는 아키텍처적 이유를 이해하고 패치하는 방법을 파악하는 것은 2026년에 Unreal Engine 프로젝트를 업그레이드하거나 출시하려는 개발자들에게 필수적입니다.
아키텍처 이해하기: Lumen Reflections vs. Global Illumination
이 버그가 왜 발생하는지 이해하려면, 내부적으로 Lumen이 reflections와 간접광을 생성하는 방식을 살펴봐야 합니다. Lumen은 레벨에 배치된 최고 디테일의 스태틱 메시(static meshes)에 직접 레이를 추적(trace)하지 않습니다. 실시간 애플리케이션에서 그렇게 하는 것은 연산 비용이 너무 크기 때문입니다. 대신, 저해상도 복셀(voxel) 구조와 베이스 컬러, 러프니스(roughness), 오파시티(opacity) 같은 표면 속성을 포함하는 2D 카드로 구성된 Lumen Scene이라는 단순화된 씬 표현을 빌드합니다. 이 데이터 세트를 Surface Cache라고 부릅니다.
정상적인 엔진 상태에서는 카메라가 환경을 움직일 때마다 Surface Cache가 계속해서 업데이트됩니다. 반사 표면에서 레이트레이싱이 필요할 때, 엔진은 이 Lumen Scene으로 레이를 쏘아 어떤 오브젝트가 보이고 어떤 빛을 내뿜는지 판별합니다. 이 구조 덕분에 전체 패스 트레이싱(path tracing) 비용의 일부만으로도 복잡하고 부드러운 reflections를 계산할 수 있습니다. 핵심은 엔진이 global indirect lighting 계산에 Lumen을 사용하는지 여부와 관계없이 Lumen Scene과 Surface Cache를 독립적으로 초기화할 수 있다는 점입니다.
PlayStation 5와 같은 최신 콘솔에서 표준 성능 프로파일을 실행해 보면, 이 두 기능을 분리하는 것이 왜 필수적인지 성능 비용 분석을 통해 명확히 확인할 수 있습니다:
- Lumen GI + Lumen Reflections: 전체 씬의 간접광 연산, Surface Cache 업데이트, 글로시 reflections 추적을 포함하여 1440p 해상도에서 약 6.5ms의 GPU 프레임 타임이 소요됩니다.
- Standalone Lumen Reflections: GI용으로 베이크된 라이트맵을 사용하면서 Surface Cache를 대상으로 reflections만 추적하는 경우, GPU 프레임 타임은 1.8ms에 불과합니다.
- Screen-Space Reflections (SSR): 현재 화면에 보이는 버퍼만을 사용하여 reflections를 추적하는 방식은 0.5ms의 GPU 프레임 타임이 걸리지만, 뷰포트 가장자리에서 심각한 비주얼 클리핑(clipping) 현상이 발생합니다.
SSR로 강제 Fallback되면, 현대적인 씬을 실감 나게 만드는 패럴랙스(parallax) 효과와 화면 바깥 오브젝트의 반사 기능이 상실됩니다. 반대로 반사를 살리기 위해 개발자에게 Lumen GI 활성화를 강제하는 것은 GPU 프레임 버짓에 4.7ms라는 거대한 세금을 부과하는 것과 같습니다. 이러한 프레임 지연은 높은 프레임 레이트를 목표로 하는 빠른 템포의 경쟁형 게임이나 액션 타이틀에서는 도저히 받아들일 수 없는 수준입니다.
Unreal Engine 5.8 Lumen Reflections 버그 진단하기
개발 중에 이 버그를 발견하려면 에디터 전용 렌더링 경로 때문에 문제를 감출 수 있는 Unreal Editor의 기본 뷰포트 동작 외의 부분을 확인해야 합니다. 이 버그는 구체적으로 Hardware Ray Tracing (HWRT)이 활성화되어 있지만 Dynamic Global Illumination Method가 비활성화되어 있을 때 발생합니다. 프로젝트가 이 버그의 영향을 받는지 확인하려면, fallback이 발생하는 정확한 설정 구성을 재현해야 합니다.
먼저 프로젝트의 렌더링 설정을 확인합니다. Project Settings > Engine > Rendering에서 Global Illumination 섹션으로 이동하여 Dynamic Global Illumination Method를 None(또는 Screen Space 같은 비Lumen 방식)으로 설정합니다. 그런 다음 Reflections 섹션으로 이동하여 Reflection Method를 Lumen으로 지정합니다. Hardware Ray Tracing 헤더 아래에서 Support Hardware Ray Tracing과 Use Hardware Ray Tracing When Available이 모두 true로 설정되어 있는지 확인합니다.
+-------------------------------------------------------------------+
| Project Settings -> Engine -> Rendering |
+-------------------------------------------------------------------+
| Dynamic Global Illumination Method: [ None / Screen Space ] |
| Reflection Method: [ Lumen ] |
| Support Hardware Ray Tracing: [ True ] |
| Use Hardware Ray Tracing: [ True ] |
+-------------------------------------------------------------------+
이 설정들을 적용한 후, Standalone 게임 인스턴스나 활성화된 PIE window에서 씬을 실행합니다. 콘솔 명령 r.Lumen.Visualize.CardPlacement 1을 실행하여 Lumen Scene을 검사합니다. Unreal Engine 5.8에서는 화면이 완전히 비어 있는 것을 볼 수 있으며, 이는 Surface Cache가 활성화되어 있지 않음을 확인해 줍니다. 이는 엔진이 카드 업데이트 파이프라인을 종료하여 reflections가 어쩔 수 없이 screen-space reflections로 fallback되었음을 의미합니다.
Unreal Insights 툴이나 표준 콘솔 명령 stat GPU를 사용해 씬을 프로파일링해 보십시오. 프로파일 패스에서 LumenReflections가 사라지고 화면 커버리지에 따라 약 0.4ms에서 0.8ms가 소요되는 ScreenSpaceReflections로 완전히 대체된 것을 확인할 수 있습니다.
프로그래밍 방식의 해결책: C++에서 Fallback 감지 및 해결하기
공식 핫픽스가 나오기 전까지는 클라이언트에서 프로그래밍 방식으로 이 상태를 감지하여 필요한 엔진 설정을 강제 적용할 수 있습니다. 이를 통해 하드웨어 레이트레이싱을 지원하는 시스템에서 렌더링 저하 현상이 유저에게 고스란히 노출되는 것을 방지할 수 있습니다. 아래 코드는 Console Manager를 쿼리하여 현재 렌더링 구성을 확인하고 충돌을 동적으로 해결하는 C++ Actor Component 구현 예시입니다.
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "HAL/IConsoleManager.h"
#include "Engine/World.h"
#include "LumenReflectionsChecker.generated.h"
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class MYGAME_API ULumenReflectionsChecker : public UActorComponent
{
GENERATED_BODY()
public:
ULumenReflectionsChecker();
protected:
virtual void BeginPlay() override;
private:
void ValidateLumenConfiguration();
};
ULumenReflectionsChecker::ULumenReflectionsChecker()
{
PrimaryComponentTick.bCanEverTick = false;
}
void ULumenReflectionsChecker::BeginPlay()
{
Super::BeginPlay();
ValidateLumenConfiguration();
}
void ULumenReflectionsChecker::ValidateLumenConfiguration()
{
// Retrieve critical engine console variables for Lumen setup
IConsoleVariable* GiMethodVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.DynamicGlobalIlluminationMethod"));
IConsoleVariable* ReflectionMethodVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.ReflectionMethod"));
IConsoleVariable* ForceLumenSceneVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Lumen.ForceLumenScene"));
if (GiMethodVar && ReflectionMethodVar)
{
int32 GiMethod = GiMethodVar->GetInt();
int32 ReflectionMethod = ReflectionMethodVar->GetInt();
// In UE 5.8, if GI is 0 (None) and Reflection is 1 (Lumen), reflections fall back to SSR.
if (GiMethod == 0 && ReflectionMethod == 1)
{
UE_LOG(LogTemp, Warning, TEXT("[LumenChecker] Warning: Lumen GI is disabled, but Lumen Reflections are active. UE 5.8 forces SSR fallback in this state."));
if (ForceLumenSceneVar)
{
// Mitigate the fallback by forcing the Lumen Scene to update
ForceLumenSceneVar->Set(1, ECVF_SetByCode);
UE_LOG(LogTemp, Log, TEXT("[LumenChecker] Applied CVar workaround: r.Lumen.ForceLumenScene set to 1."));
}
}
}
}
이 컴포넌트는 메인 게임 스테이트(game state)나 초기화용 액터(actor)에 부착하여 사용할 수 있습니다. 게임이 시작되면 스크립트는 프로젝트 설정이 버그가 발생하는 구성과 일치하는지 확인합니다. 일치하는 경우, 프로그래밍 방식으로 r.Lumen.ForceLumenScene을 1로 설정합니다. 이렇게 하면 Global Illumination 시스템이 요청하지 않더라도 렌더러가 Surface Cache를 유지하도록 강제하여, reflections 기능을 완전히 활성화된 상태로 유지할 수 있습니다.
수동 해결 방법 및 엔진 소스 수정
Console Variables를 수정하기 위해 런타임 C++ 스크립트를 실행하고 싶지 않은 개발자를 위해, fallback 문제를 해결하는 두 가지 주요 수동 방법이 있습니다. 설정 파일을 직접 수정하거나 엔진의 소스 코드를 패치하는 것입니다. 두 접근 방식 모두 사용 중인 Unreal Engine의 런처 버전 또는 커스텀 소스 빌드 여부에 따라 유효합니다.
Workaround 1: Console Variables를 통한 설정 오버라이드
Epic Games Launcher 버전의 Unreal Engine 5.8을 사용 중이라면 엔진 코드를 직접 수정할 수 없습니다. 대신 설정 파일을 통해 엔진이 Lumen Scene을 강제로 유지하도록 해야 합니다. 프로젝트 디렉토리로 이동하여 Config/DefaultEngine.ini 파일을 엽니다.
[/Script/Engine.RendererSettings] 카테고리 아래에 다음 줄을 추가합니다:
r.DynamicGlobalIlluminationMethod=0
r.ReflectionMethod=1
r.Lumen.ForceLumenScene=1.Lumen.Reflections.AllowWithoutGI=1
r.Lumen.ForceLumenScene을 1로 설정하면, GI가 비활성화되었을 때 Lumen Scene을 사용하지 않음으로 표시하는 Rendering Pipeline의 최적화 패스를 오버라이드합니다. 이로 인해 엔진은 Surface Cache 카드를 생성하고 업데이트하는 데 필요한 GPU 메모리와 컴퓨트 패스(compute passes)를 강제로 할당하게 됩니다. 이 방법을 통해 reflections는 복구되지만, 이전 버전에 있었던 최적화 컨텍스트 없이 업데이트를 수행하므로 UE 5.7과 비교했을 때 GPU 베이스 패스(base pass) 비용이 약간 증가할 수 있다는 점을 유념해야 합니다.
Workaround 2: 엔진 소스 코드 수정
Unreal Engine 5.8을 소스 코드 빌드로 컴파일하여 사용한다면 버그의 근본 원인을 직접 패치할 수 있습니다. 이 Regression의 근본 원인은 엔진의 프라이빗 렌더링 파일 중 Private/Lumen/LumenScene.cpp에 위치한 FDeferredShadingSceneRenderer::InitLumenScene 함수 내부에 있습니다. UE 5.8에서는 Lumen Scene이 필요한지 여부를 판단하는 조건 검사식이 최적화되었으나, 이 과정에서 실수로 reflection 설정 검사가 누락되었습니다.
이를 해결하려면 LumenScene.cpp 파일을 열고 bNeedLumenScene이 정의된 위치를 찾습니다. 잘못된 코드와 수정된 코드는 다음과 같습니다:
- // Faulty check in UE 5.8 that ignores reflection settings
- const bool bNeedLumenScene = Scene->DynamicGIProjectSetting == EEDynamicGlobalIlluminationMethod::Lumen;
+ // Corrected check restoring reflections-only compatibility
+ const bool bNeedLumenScene = Scene->DynamicGIProjectSetting == EEDynamicGlobalIlluminationMethod::Lumen || Scene->ReflectionProjectSetting == EEReflectionMethod::Lumen;
이 라인을 수정하고 엔진을 다시 빌드합니다. 이렇게 하면 UE 5.7에서 사용되었던 파이프라인 로직이 복구되어, Global Illumination 방식과 상관없이 Lumen reflections가 선택되면 렌더러가 Lumen Scene을 정상적으로 초기화합니다. 이 방법은 팀원들을 혼란스럽게 하거나 설정 파일을 어지럽히는 CVar 오버라이드를 피할 수 있기 때문에 문제를 해결하는 가장 깔끔한 방법입니다.
다운스트림 영향: 클라이언트 프레임 드랍 및 Multiplayer Desync
그래픽 버그는 흔히 단순한 비주얼 이슈로 간주되지만, 부수적인 악영향이 게임 아키텍처 전반으로 파급될 수 있습니다. 이 버그를 발견한 개발자들의 첫 번째 반응은 대개 reflections를 복구하기 위해 단순히 Lumen GI를 다시 켜는 것입니다. 그러나 클라이언트에 4ms에서 6ms에 달하는 GPU 연산 부하를 추가하는 것은 심각한 프레임 레이트 저하를 유발할 수 있으며, 이는 Multiplayer Desync 문제로 이어질 수 있습니다.
Multiplayer 게임에서는 피직스 시뮬레이션(physics simulation)과 유저 입력(input) 처리가 클라이언트의 프레임 틱 레이트와 밀접하게 연동되어 있습니다. 카메라를 회전하는 동안 reflection 패스가 GPU에 과부하를 주는 등 클라이언트가 갑작스러운 렌더링 병목(stall)을 겪게 되면 클라이언트의 시뮬레이션 프레임 타임이 급증합니다. 이 지연으로 인해 네트워크 패킷이 늦게 전송되거나 비순차적으로 처리되어, 결과적으로 눈에 띄는 렉(lag)이 발생하고 서버 보정(corrections)이 가해집니다. 이러한 성능 스파이크가 게임의 멀티플레이어 환경을 저해하지 않도록 하려면, UEFN 및 Unreal Engine 멀티플레이어에서 플레이어 위치 desync를 해결하는 방법 가이드를 참고하여 해결 방법을 확인해 보시기 바랍니다.
나아가, 이러한 렌더링 문제는 클라이언트 사이드 그래픽 설정과 서버 로직을 분리하는 것이 왜 중요한지 잘 보여줍니다. 헤드리스 Dedicated Server는 렌더링 파이프라인, 머티리얼, 포스트 프로세스 볼륨을 컴파일하거나 로드해서는 안 됩니다. 서버 실행 파일을 빌드할 때 이러한 애셋들을 스트리핑(strip)하지 않으면 메모리 점유율이 늘어나고 구동 시간이 느려져 Matchmaker 응답 속도 저하로 이어질 수 있습니다. 서버 빌드를 최적화하는 자세한 방법은 Unreal Engine Dedicated Server 애셋 스트리핑을 마스터하는 방법 아티클에서 확인하실 수 있습니다.
horizOn으로 설정 오버헤드 해결하기
로컬 PC에서 unreal engine 5.8 lumen reflections bug 같은 렌더링 버그를 수정하는 것은 절반의 해결책에 불과합니다. 게임을 라이브로 서비스하기 시작하면 수천 가지의 다양한 클라이언트 PC 사양에 맞춰 그래픽 프로파일, Console Variable 오버라이드, 엔진 설정을 관리해야 합니다. 로컬 설정에 CVars를 하드코딩해 두면 엔진의 마이너 업데이트에서 또 다른 렌더링 Regression이 발견되었을 때 전체 게임 클라이언트를 다시 컴파일하고 패키징하여 배포해야만 합니다.
이러한 설정 관리 오버헤드를 줄이는 데 있어 horizOn은 게임 개발자에게 매우 유용한 도구입니다. 렌더링 문제를 해결하기 위해 대용량 클라이언트 업데이트를 배포하는 대신, 저희 플랫폼을 사용하면 중앙 집중식 Backend에서 게임 설정을 동적으로 관리할 수 있습니다. horizOn의 원격 설정(remote configuration) 서비스를 사용하면 다양한 하드웨어 사양에 맞는 타겟 프로파일을 정의하고 실시간으로 업데이트할 수 있습니다.
예를 들어, 플레이어가 게임을 실행할 때 클라이언트는 감지된 GPU 및 엔진 버전 정보를 Backend에 전달하며 쿼리를 보냅니다. 서버는 설정 규칙에 따라 이 데이터를 평가하고 최적화된 CVar 목록을 반환합니다. 만약 플레이어가 미들급 그래픽 카드에서 UE 5.8로 게임을 실행한다면, Backend에서 동적으로 r.Lumen.ForceLumenScene=1을 전달합니다. 이를 통해 복잡한 클라이언트 사이드 프로파일을 직접 작성하거나 긴급 패치를 배포하지 않고도 reflections를 완벽하게 유지할 수 있습니다.
프로덕션 환경의 Lumen 설정 베스트 프랙티스
Lumen reflections나 글로벌 일루미네이션(global illumination)을 사용하는 게임을 출시할 때, 구조화된 QA 프로세스를 거치면 비주얼 Regression이 플레이어에게 도달하는 것을 방지할 수 있습니다. 다음은 개발 파이프라인에 통합할 수 있는 4가지 베스트 프랙티스입니다:
- GBuffer 검사 자동화: 특정 렌더링 플래그를 사용하여 뷰포트 이미지를 캡처하는 자동화 테스트를 CI/CD pipeline에 구축하십시오. 이 테스트를 통해 reflection 채널이 빈 화면으로 fallback되는 대신 유효한 ray-traced 데이터를 포함하고 있는지 검증합니다.
- 최적화 진행 시 GI와 Reflections 분리: GI를 비활성화하고 Lumen reflections는 활성화한 상태로 게임을 테스트해 보십시오. 이를 통해 중저사양 시스템에서 스펙큘러 하이라이트를 유지하면서 baked lighting 솔루션을 사용했을 때의 성능 이점을 평가할 수 있습니다.
- 시작 시 CVar 검증 실행: 게임의 초기 로딩 단계에서
r.DynamicGlobalIlluminationMethod및r.ReflectionMethod와 같은 Console Variables의 상태를 검사하는 런타임 검증 스크립트를 구현하여 fallback이 트리거되지 않도록 합니다. - 동적 클라이언트 프로파일 적용: 프로젝트 바이너리에 그래픽 프리셋을 하드코딩하지 마십시오. 동적 설정 도구를 사용해 렌더링 변수를 실시간으로 조정하면 전체 클라이언트 업데이트를 진행하지 않고도 엔진의 Regression에 즉각 대응할 수 있습니다.
게임의 설정 관리를 단순화하고 안정적인 Dedicated Server를 구축할 준비가 되셨나요? 지금 horizOn에 가입하거나 개발자 문서를 확인하여 동적 설정 업데이트를 Unreal Engine 파이프라인에 통합하는 방법을 알아보십시오.
출처: UE 5.8 Release - Lumen Reflections not working unless Lumen GI enabled