블로그로 돌아가기

Unreal Engine 모바일 최적화: MetaHumans와 PCG를 60 FPS로 구동하기

게시일 2026년 6월 19일
Unreal Engine 모바일 최적화: MetaHumans와 PCG를 60 FPS로 구동하기

핵심 요약

본 가이드는 Unreal Engine에서 MetaHumans 및 PCG 등 차세대 고화질 그래픽 요소를 모바일 환경에 맞춰 60 FPS로 최적화하는 핵심 기법을 설명합니다. bone skinning 하드웨어 한계를 극복하기 위한 DefaultEngine.ini 설정 조율, Hair Cards 대체 기법, 그리고 runtime 부하를 제거하기 위한 PCG graph의 HISM pre-baking 워크플로우를 다룹니다. 아울러 모바일 네트워크 변동성 대응과 backend 인프라 경감을 위해 horizOn 플랫폼을 도입해 최적화 프로세스를 완결하는 방안을 제시합니다.

The Mobile Barrier: Bringing Next-Gen Visuals to Mobile

개발자 워크스테이션에서 완벽하게 120 FPS로 실행되던 아름다운 PC 프로젝트가 모바일 패키지를 테스트하는 순간 frame rate가 한 자릿수로 급락하고, 기기가 과열되며, skinning buffer overflow로 인해 GPU가 크래시되는 경우가 있습니다. MetaHumans, Procedural Content Generation (PCG), Substrate material 같은 하이엔드 기능들은 PC와 콘솔에서는 눈부시게 아름답지만, 모바일 기기의 성능을 밑바닥까지 끌어내리기 쉬운 악명 높은 요소들입니다. 모바일 GPU와 CPU는 memory bandwidth가 매우 귀중한 자원인 극도로 제한된 열 및 전력 환경에서 작동합니다. 이러한 차세대 기능들을 모바일 배포에 맞춰 조정하는 것은 단순히 설정 체크박스 하나를 켜는 문제가 아닙니다. 이는 bone skinning 제한, groom 구조, procedural baking 워크플로우, 그리고 material shading 복잡성에 대한 깊고 체계적인 이해를 필요로 합니다.

The GPU Skinning and Bone Limit Challenge

The GPU Skinning Bottleneck on Mobile

Skinned skeletal mesh는 GPU로 전송되기 전에 vertex 및 bone의 청크(chunk)로 분할됩니다. 각 청크는 단일 draw call로 처리되며, 모바일 GPU는 동시에 skinning할 수 있는 bone matrix 개수에 엄격한 하드웨어 제한이 있습니다. 이 제한은 vertex shader에서 사용할 수 있는 uniform vector의 수에 의해 결정됩니다. 기본 MetaHuman 캐릭터 skeleton은 600개가 넘는 bone을 포함하고 있어 모바일 제한을 쉽게 초과하며, 이로 인해 렌더링 오류, vertex tearing 또는 완전한 GPU hangs 현상이 발생할 수 있습니다.

이러한 하드웨어 제약을 우회하려면, 단일 draw call이 특정 수 이상의 bone을 참조하지 않도록 engine이 skeletal mesh 청크를 강제로 분할하게 해야 합니다. 이는 skinning 호환성 설정을 조정하여 달성할 수 있습니다. 이 설정을 적용하지 않으면 캐릭터 모델이 Android 및 iOS 기기에서 올바르게 skinning되지 않아, 정지되거나 심하게 왜곡된 mesh가 렌더링됩니다.

Configuring the DefaultEngine.ini

bone skinning 제한 문제를 해결하려면 프로젝트의 DefaultEngine.ini 설정 파일을 수정해야 합니다. 프로젝트 루트의 Config 폴더에서 이 파일을 찾으십시오. [ConsoleVariables] 섹션 아래에 다음 줄을 추가합니다.

[ConsoleVariables]
Compat.MAX_GPUSKIN_BONES=75

이 console variable은 shader compiler가 skinning 청크당 최대 bone 수를 75개로 제한하도록 지시합니다. 이는 구형 또는 중보급형 모바일 GPU를 위한 엄격한 하드웨어 제한입니다. 이 값을 낮게 설정하면 skeletal mesh 컴파일러가 mesh를 더 많은 수의 청크로 강제 분할하게 된다는 점에 유의해야 합니다. 이는 렌더링 호환성 문제는 해결하지만, 청크 수가 늘어나면 draw call이 증가하므로 성능 병목 현상이 CPU render thread로 이동할 수 있습니다.

Reducing Bone Counts and Component Stripping

완전한 얼굴 표정(facial articulation)이 필요 없는 배경 캐릭터나 NPC(non-player characters)의 경우, skeleton을 대폭 축소해야 합니다. 예를 들어 손가락, 발가락, 얼굴 표정용 bone을 제거하면 캐릭터의 총 bone 수를 600개 이상에서 75개 미만으로 줄일 수 있습니다. 이를 통해 draw call 증가 없이 캐릭터 mesh를 단일 청크로 렌더링할 수 있게 됩니다.

multiplayer 게임을 위해 dedicated server도 배포하는 경우, client-side 최적화는 전체 작업의 절반에 불과합니다. 렌더링용 에셋을 완전히 제거하여 server-side 성능 역시 최적화해야 합니다. 서버 메모리 오버헤드를 줄이고 CPU 성능을 최적화하려면 how to master Unreal Engine dedicated server asset stripping 가이드를 확인해 보시기 바랍니다.

Optimizing MetaHuman Hair: Groom Strands vs. Hair Cards

The Strand Rendering Cost

Epic의 groom strand rendering 기술은 개별 머리카락 곡선을 동적으로 그려냅니다. 하이엔드 데스크톱 GPU에서는 매우 상세한 머리카락을 표현하지만, 비용이 엄청나게 많이 듭니다. strand rendering은 depth sorting 및 shadow map 생성을 위해 compute shader 패스에 의존하며, 이는 상당한 pixel fill rate와 memory bandwidth를 소모합니다.

모바일 기기에서 strand rendering은 완전히 지원되지 않거나, 단일 캐릭터의 머리카락에만 15ms 이상의 GPU 시간을 소모하는 등 감당하기 힘든 비용이 듭니다. 모바일 GPU는 프레임당 수십만 개의 개별 머리카락 곡선을 정렬하고 shading하는 데 필요한 생(raw) memory bandwidth가 부족합니다.

Implementing Hair Cards

해결책은 strand 기반 groom을 Hair Cards로 교체하는 것입니다. Hair Cards는 미리 렌더링된 머리카락 텍스처가 매핑된 평평하고 단순화된 폴리곤 mesh를 사용하여 머리카락을 표현합니다. 이 방식은 모바일 forward render path와 호환성이 매우 높습니다.

Hair Cards를 구현하려면 MetaHuman Creator를 열고 캐릭터의 card 기반 groom LOD를 생성하도록 설정하십시오. strand 기반 머리카락을 card 기반 groom으로 교체하면 Apple A15나 Snapdragon 8 Gen 1 같은 최신 모바일 칩에서 단일 캐릭터의 머리카락 렌더링 시간을 약 18.2ms에서 0.9ms로 대폭 줄일 수 있습니다. 이러한 막대한 절감 효과 덕분에 렌더링 리소스를 gameplay 요소나 주변 환경 디테일에 더 많이 할당할 수 있게 됩니다.

Disabling Post-Process Anim Blueprints

MetaHumans는 보조 bone의 움직임, 보정 근육 모양, 관절 역학을 제어하기 위해 post-process animation blueprint를 사용합니다. PC에서는 사실적인 피부 움직임을 더해주지만, 매 프레임 CPU에서 복잡한 skeletal 계산을 수행해야 합니다. 모바일의 경우, 이러한 CPU 오버헤드는 game thread의 성능 병목을 쉽게 유발할 수 있습니다.

모바일 기기에서 CPU 연산 주기를 확보하기 위해 post-process animation blueprint를 비활성화할 수 있습니다. 이는 skeletal mesh component에서 bDisablePostProcessAnims = true로 설정하여 수행합니다. 이 post-process들을 비활성화하면 일반적인 모바일 하드웨어에서 최대 4.5ms의 CPU 프레임 시간을 절약할 수 있습니다.

Optimizing PCG for Mobile Environments

The Overhead of Runtime PCG Execution

Procedural Content Generation (PCG) framework를 사용하면 규칙과 볼륨을 기반으로 static mesh, foliage, actor를 배치하여 환경을 동적으로 구성할 수 있습니다. 하지만 모바일 CPU에서 runtime에 PCG graph를 실행하면 심각한 성능 끊김(hitch) 현상이 발생합니다. 전형적인 runtime graph 생성은 level loading이나 player spawning 중에 game thread를 1.5초에서 3초 동안 멈추게 만들 수 있습니다.

multiplayer 게임에서 이러한 끊김은 꽤 위험합니다. packet loss를 유발하고 client-server 상태 비동기화(state desynchronization)를 초래할 수 있기 때문입니다. 높은 성능을 유지하기 위해 editor에서 PCG graph를 pre-bake해야 합니다. 이를 통해 게임을 패키징하기 전에 procedural 인스턴스들을 static geometry로 변환할 수 있습니다.

Step-by-Step PCG Baking Workflow

  1. PCG Volume 선택: Unreal Editor viewport에서 환경 요소를 포함하는 PCG volume을 선택합니다.
  2. Generate 및 검사: 볼륨의 details panel에서 Generate를 클릭하여 에셋의 procedural 배치 상태를 미리 확인합니다.
  3. Export to Actor: PCG 유틸리티 메뉴에서 Export to Actor 옵션을 찾습니다.
  4. Instanced Mesh 선택: 대상 포맷으로 **Hierarchical Instanced Static Mesh (HISM)**를 선택합니다. 이 인스턴스 그룹은 동일한 모든 mesh를 단일 GPU draw call로 그리기 때문에 모바일 GPU에 고도로 최적화되어 있습니다.
  5. Clear the Graph: 내보내기(export)를 마친 후, PCG volume의 생성 트리거를 Editor Only로 설정하거나 볼륨을 비웁니다. 이를 통해 runtime에 engine이 graph를 재생성하려는 시도를 차단할 수 있습니다.

Dynamic HISM Culling and Streaming

PCG 인스턴스를 HISM으로 bake했다면, 이들의 culling 거리를 설정해야 합니다. HISM은 인스턴스별 culling을 지원하여, 카메라로부터 일정 거리 이상 떨어진 인스턴스는 그려지지 않도록 합니다. HISM component의 details panel에서 Start Cull DistanceEnd Cull Distance를 설정하십시오. 모바일의 경우, 전체 표시 폴리곤 수를 모바일 GPU 예산 내로 유지하기 위해 cull 거리를 5000에서 8000 유닛으로 설정하는 것이 좋습니다.

Production C++ Optimization Script

runtime에 이러한 최적화를 자동화하기 위해 커스텀 helper class를 작성할 수 있습니다. 다음 C++ 코드는 모바일 기기에서 MetaHuman을 생성할 때, 대상 플랫폼을 확인하고, 프로그래밍 방식으로 하위 LOD를 강제하고, post-process animation blueprint를 비활성화하며, groom component가 card 기반 렌더링을 사용하도록 강제하는 방법을 보여줍니다. 이를 UMetaHumanMobileOptimizer와 같은 클래스에 구현할 수 있습니다:

#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "Components/SkeletalMeshComponent.h"
#include "GroomComponent.h"
#include "MetaHumanMobileOptimizer.generated.h"

UCLASS()
class MYPROJECT_API UMetaHumanMobileOptimizer : public UBlueprintFunctionLibrary

{
    GENERATED_BODY()

public:
    UFUNCTION(BlueprintCallable, Category = "Optimization")
    static void OptimizeMetaHumanForMobile(AActor* MetaHumanActor)
    {
        if (!MetaHumanActor)
        {
            return;
        }

        // Apply optimizations exclusively on Android and iOS platforms
        #if PLATFORM_ANDROID || PLATFORM_IOS
        TArray<USkeletalMeshComponent*> SkeletalComponents;
        MetaHumanActor->GetComponents<USkeletalMeshComponent>(SkeletalComponents);

        for (USkeletalMeshComponent* MeshComp : SkeletalComponents)
        { 
            if (MeshComp)
            {
                // Force a low LOD (LOD 3 or 4) to bypass dense meshes
                MeshComp->SetMinLOD(3);
                MeshComp->SetForcedLOD(3);

                // Disable expensive post-process animation blueprints
                MeshComp->bDisablePostProcessAnims = true;

                // Adjust animation tick rate to only calculate when visible
                MeshComp->VisibilityBasedAnimTickOption = EVisibilityBasedAnimTickOption::OnlyTickPoseWhenRendered;

                // Strip physics asset to avoid CPU collision overhead on cosmetic joints
                MeshComp->SetPhysicsAsset(nullptr);
            }
        }

        TArray<UGroomComponent*> GroomComponents;
        MetaHumanActor->GetComponents<UGroomComponent>(GroomComponents);

        for (UGroomComponent* GroomComp : GroomComponents)
        {
            if (GroomComp)
            {
                // Force the groom to use card rendering instead of strands
                GroomComp->SetUseCards(true);
            }
        }
        #endif
    }
};

이 helper function은 캐릭터의 BeginPlay 이벤트에서 또는 MetaHuman actor를 생성한 직후에 호출될 수 있습니다. 조건부 컴파일 매크로(PLATFORM_ANDROID || PLATFORM_IOS)를 사용하면 compiler가 PC 및 콘솔 빌드에서 이러한 오버라이드를 완전히 제외하므로, cross-platform에서 원본 visual fidelity를 자동으로 보존할 수 있습니다.

Adapting Substrate Materials for Mobile GPUs

What is Substrate?

Substrate는 기존 Unreal Engine의 shading model을 모듈식 다층 material 프레임워크로 대체합니다. Substrate를 사용하면 개발자가 여러 shading slab을 쌓을 수 있습니다(예: 거친 금속 레이어 위에 광택이 나는 clear coat 레이어를 직접 배치). Substrate는 하이엔드 시네마틱 에셋을 표현하는 데 매우 탁월하지만, 모바일 렌더러에서는 상당한 성능 장애물이 됩니다.

모바일 GPU는 GPU 코어와 온칩 프레임 버퍼 사이의 메모리 버스가 주 병목 지점인 타일 기반 렌더링(tiled rendering) 아키텍처에 크게 의존합니다. 복잡한 Substrate material은 프레임 버퍼에 기록되는 bytes per pixel (BPP)을 증가시켜, 쓰로틀링(thermal throttling) 및 frame rate 저하를 유발합니다.

Managing Material Complexity via Quality Level Switches

모바일에서 Substrate material의 성능을 유지하려면 Material Editor 내에서 Material Quality Level SwitchFeature Level Switch 노드를 사용해야 합니다. 이 노드들을 사용하면 대상 플랫폼에 따라 material graph를 단순화할 수 있습니다.

모바일 플랫폼의 경우 다층 Substrate 블렌딩을 우회하여 material graph를 간소화하십시오. 대신 에셋의 시각적 스타일과 유사한 단일 slab으로 대체(fall back)하십시오. material 노드를 품질 스위치(quality switch)를 통해 라우팅하면 쓰기 대역폭을 픽셀당 32바이트에서 표준 8바이트로 줄일 수 있으므로, 기기 발열을 줄이고 안정적인 frame rate를 확보할 수 있습니다.

5 Actionable Best Practices for Mobile Optimization

  1. 모든 PCG graph를 HISM으로 pre-bake: runtime에 클라이언트에서 PCG graph를 실행하지 마십시오. editor 개발 과정에서 graph를 Hierarchical Instanced Static Mesh (HISM)로 미리 bake하고 적절한 start/end cull 거리를 설정하십시오.
  2. 전역적으로 bone 수 제한: 프로젝트의 DefaultEngine.ini 파일에 Compat.MAX_GPUSKIN_BONES=75를 추가하여 버퍼 오버플로우를 일으키지 않고 모바일 GPU에서 skeletal mesh가 올바르게 렌더링되도록 하십시오.
  3. Card 기반 groom만 사용: 모바일 프로필에서는 strand 기반 groom을 비활성화하십시오. card 기반 머리카락 렌더링은 캐릭터당 GPU 프레임 시간을 18ms에서 1ms 미만으로 단축시킵니다.
  4. Material Quality Switch 활용: Substrate material에 Material Quality Level Switch 노드를 구현하여 모바일 플랫폼에서 복잡한 shading 레이어를 단일 slab으로 단순화하고 GPU 대역폭을 줄이십시오.
  5. Post-process animation blueprint 비활성화: 모바일 기기의 캐릭터 skeletal component에서 bDisablePostProcessAnims = true로 설정하여 game thread의 귀중한 CPU 연산 주기를 확보하십시오.

The Multiplayer and Backend Equation

Beyond Rendering: Mobile Network Optimization

cross-platform multiplayer 게임을 개발할 때, client-side 최적화는 전체 퍼즐의 일부에 불과합니다. 모바일 기기는 셀룰러 데이터(5G/4G)와 Wi-Fi 사이를 전환하며 자주 네트워크 변동을 겪게 됩니다. 이러한 변동은 packet loss, jitter, 높은 latency 스파이크를 유발합니다.

네트워크 동기화 코드가 견고하지 않다면, 이 latency 스파이크로 인해 actor replication의 동기가 맞지 않아 world state를 파괴하는 the Unreal Engine multiplayer sync bug가 발생할 수 있습니다. 모바일 네트워크 제약 속에서 multiplayer 상태를 제어하는 것은 복원력이 뛰어난 network driver, delta compression, server-authoritative reconciliation이 필요한 복잡한 문제입니다.

Offloading Infrastructure with horizOn

복원력 높은 multiplayer backend를 직접 구축하고 유지 관리하는 것은 엄청난 엔지니어링 리소스가 소모되는 작업입니다. load balancer를 프로비저닝하고, 글로벌 database replication을 관리하며, matchmaking 로직을 구현하고, 모바일 결제(billing)를 처리해야 합니다. 이러한 인프라 작업은 수개월의 개발 기간과 지속적인 유지 보수를 요구합니다.

horizOn을 활용하면 이러한 backend 서비스가 사전에 설정되어 제공됩니다. horizOn은 게임 개발자에게 세션 matchmaking, 저지연 state synchronization, database persistence, cross-platform 인증(authentication) 기능을 별도 구축 없이 기본 제공합니다. 이를 통해 서버 클러스터 및 데이터베이스 확장성 관리에 매달리는 대신, 클라이언트 최적화와 게임 루프 폴리싱에 집중할 수 있습니다.

Conclusion and Next Steps

MetaHumans 및 PCG 같은 차세대 기능을 모바일에서 최적화하려면 렌더링 버젯, skeletal mesh 컴파일, 그리고 material shading 복잡성에 대한 엄격한 통제가 필수적입니다. procedural 에셋을 pre-bake하고, bone 개수 제한을 적용하며, card 기반 머리카락 렌더링을 사용함으로써 모바일 기기에서도 뛰어난 퀄리티의 cross-platform 경험을 제공할 수 있습니다.

multiplayer backend 규모를 확장할 준비가 되셨나요? horizOn을 무료로 체험하거나 API docs를 확인하여 인프라 구성을 간소화하고 PC, 콘솔, 모바일 전체에서 플레이어 상태를 동기화하는 방법을 알아보십시오.


출처: Tutorial: Optimizing Next Gen Features for Mobile Game Development

이 대시보드는 다음에 의해 애정을 담아 만들어졌습니다 Projectmakers

© 2026 projectmakers.de

unknown-v1.94.4 / unknown-v--