아래는 언리얼 엔진 프로젝트에서 발생한 프레임 드롭을 해결한 과정을 기록한 글이다.

 

 

목차

     

     


     

     

     

     


    문제 발생


     

     

    프레임 드랍

     

    게임 시작과 동시에 프레임 드랍(Frame Drop)이 발생했다.

     

     


     

     

     

    프로파일링 및 최적화 하기


     

     

    라이트 문제 

     

    [ 문제 파악하기 ]

     

    에디터에서 Optimization Viewmodes - Light Complexity 를 눌러 라이트 연산량을 시각적으로 체크했다.

    검은색일수록 연산량이 적고 검은색 < 파랑색 < 초록색 < 노란색 < 빨간색 < 분홍색 < 흰색 순서로 연산량이 많다. 

    해당 화면을 보고 라이트 연산량이 많다는 것을 파악했다. 

     

     

     

    PointLight 라이트의 Attenuation 범위가 너무 커서 겹쳐지는 부분이 많다. (Attenuation이 4000cm로 너무 컸다).

    물체가 여러개의 라이트로 겹쳐져서 연산되어 연산량이 너무 많아졌다.  겹치는 부분이 많을수록 성능 저하가 많이 일어난다.

     

     

     

    [ 해결 방안 ]

     

    PointLight 라이트의 Attenuation 범위를 500으로 줄였다. 참고로 Attenuation의 단위는 cm다.

     

    추가로 고려해볼 사항으로는 movable로 설정된 라이트들을 Static으로 변경하고 라이팅을 빌드하는 것이다.

    이것은 맵 디자인에 관련된 것이므로 아트 직군과 상의해봐야 하는 문제다. 프레임이 제대로 나오는 상황이 아니라면 아트 직군은 비주얼적인 완성도를 위해 movable로 남겨두고 싶을 확률이 크다.  


     

     

     

    파티클 (Particle)

     

    [ 문제 파악하기 ]

    맵에 배치된 안개 파티클을 연산하는데 드는 비용이 너무 컸다. 안개(NS_Fog)를 바라보는 것만으로 프레임이 10으로 줄어든다.

    좌측에 희여멀건한게 안개다.

     

     

     

    일단, 해당 파티클의 Spawn Rate이 지나치게 높았다.

     

     

    NS_Fog의 Lifetime. Material의 Opacity가 0.01 곱셈으로 처리되어 원하는 느낌을 내기위해 너무 많은 파티클을 스폰해서 사용했다. (0.01이면 너무 투명하게 보여서 안개가 잘 안 보인다.) 또한 Material의 노이즈의 값이 너무 크다.

     

     

     

    [ 해결 방안 ]

     

    Opacity Rate 값을 1로 올리고 Spawn Rate을 0.5로 낮춰 원하는 효과를 내고 드로우 콜은 줄였다. 

     


     

     

    매쉬 (LOD 설정으로 해결)

     

    [ 문제 파악하기 ]

     

    Tools - Audit - Statics 에 들어가 레벨에 배치된 파일들을 체크한다.

    먼저 Primitive Stats 에서 지나치게 큰 파일(액터, 매쉬 등)이 있는지 확인한다.

    파일 사이즈가 큰 것들을 확인했다.

     

     

    텍스처 해상도를 추가로 확인한다.

    4K 해상도의 텍스처를 사용하고 있었다.

     

    위에서 찾은 StaticMesh를 확인.

    맵에 배치된 동물 머리뼈 매쉬가 너무 커서 드로우콜이 많이 일어났다. 아래 이미지처럼 디테일한 모양을 위해 버택스 수가 너무나도 크게 할당되어 있었다. (트라이앵글이 약 12,500개...)

     

     


    [ 해결 방안 ]

    텍스처의 사이즈를 FHD 사이즈로 줄였다.

    LOD Settings에 들어가서 LOD 세팅을 다시 적용했다. LOD를 자동 생성하여 Vertex와 Triangle 수를 줄였다.

     

    참고) 요즘은 거리비가 아닌 ScreenSize에 따라 LOD를 구분해야 한다. 


     

     

    에셋 로딩. 게임 초반에 Hitch 튀는부분. 

     

    BP_GameInstance

    • 비동기 로드(Async Load), Async Tak도 확인
    • 게임이 시작하면 필요한 에셋들을 비동기 로딩하도록 만들어 놓았다.

    그러다 중간에 Load Asset Block을 해버리면 중간에 모두 비동기하던 것들을 다 하고 돌아와서 로드해야 하는데 그 과정에서 튀는 현상이 발생한다.

     

    정리해서 다시말하면, 비동기 에셋 로딩 방식에서 Load Asset Blocking 노드로 인해 병목 현상이 발생하였다.

     

     

     


     

     

    메모리 릭 (Memory Leak)

     

    [ 문제 파악하기 ]

     

    에디터에서는 문제가 발생하지 않지만 게임을 패키징해서 배포했더니 문제가 발생했다. 게임을 3~4일 켜두니 게임이 꺼지는 현상이 발생했다. 몇일 동안 메모리 누수가 발생하여 메모리가 넘쳐 게임이 꺼지게 된 것이다.

     

    메모리 누수는 찾기가 어렵다. 이런 경우, 언리얼 인사이트로 확인하는게 좋다.

     

     

     

    [ 해결 방안 ]

    메모리 누수(Memory Leak) 찾기

    • 정적 분석
    • AIC_Boss
    • 언리얼 LLM 태그

     

    에디터 실행 파일 - 바로가기로 만들기 - 우클릭 - 속성에
    -Trace=default,memory 를 추가하면 언리얼 인사이트에서 메모리 인사이트를 볼 수 있다.

     

    변경 전

    "C:\Program Files\Epic Games\UE_5.3\Engine\Binaries\Win64\UnrealEditor.exe"

     

    변경 후

    E:\Unreal\UE5_3\폴더명\프로젝트명.uproject -trace=default,memory

     

     

     

    위와 같이 수정하면 Trace에서 Memory 부분을 클릭할 수 있게 된다. 

    Memory Insights 탭 → 우측에 ' Rule : Memory Leak '을 클릭 → 시점 A,B,C 지정해서 RunQuery 버튼 클릭

     

    void ARPGPlayerControllerBase::TickActor(float DeltaTime, ELevelTick TickType, FActorTickFunction& ThisTickFunction)
    {
    	Super::TickActor(DeltaTime, TickType, ThisTickFunction);
    
    	// Add a new stats capture
    	StatsCaptures.Add(*new FTickStatsData(DeltaTime)); // new로 동적할당 하였지만 해당 메모리를 해제(Delete)하는 부분이 없다.
    
    	// Send stat captures to analytics server in bundles
    	if (StatsCaptures.Num() > 100)
    	{
    		SendStatsToServer();
    		StatsCaptures.Empty();
    	}
    }

     

     

     

     

     

     

    https://dev.epicgames.com/documentation/en-us/unreal-engine/memory-insights-in-unreal-engine?application_version=5.0