Unreal Engine Mobile Optimization: MetaHumans ve PCG'yi 60 FPS'te Çalıştırma
Özet olarak
Bu rehber, Unreal Engine projelerinde MetaHumans ve PCG gibi yeni nesil özellikleri mobil cihazlarda 60 FPS çalıştırmak için gereken optimizasyon tekniklerini açıklamaktadır. Donanım bone limitlerini aşmak, hair cards ve static mesh bake yöntemlerini kullanmak gibi pratik yöntemlerin yanı sıra runtime C++ optimizasyon script'ine yer verilmektedir. Ayrıca mobil ağ dalgalanmalarına karşı multiplayer senkronizasyon problemleri ele alınmakta ve horizOn backend çözümleri tanıtılmaktadır.
Mobil Bariyer: Yeni Nesil Görselleri Mobile Taşımak
Geliştirici iş istasyonunuzda kusursuz bir şekilde 120 FPS ile çalışan harika PC projeniz, mobil paketi test ettiğiniz an tek haneli kare hızlarına düşüyor, hedef telefon ısınıyor ve GPU bir skinning buffer overflow hatası nedeniyle çöküyor. MetaHumans, Procedural Content Generation (PCG) ve Substrate materyalleri gibi üst düzey özellikler PC ve konsollarda büyüleyici görünse de mobil cihazları dize getirmeleriyle bilinirler. Mobil GPU'lar ve CPU'lar, bellek bant genişliğinin son derece değerli bir kaynak olduğu, oldukça kısıtlı termal ve güç bütçeleri içinde çalışır. Bu yeni nesil özellikleri mobil dağıtıma uyarlamak sadece bir konfigürasyon kutucuğunu işaretlemekten ibaret değildir; bone skinning limitleri, groom yapıları, prosedürel bake iş akışları ve materyal shading karmaşıklıkları hakkında derin ve sistematik bir anlayış gerektirir.
GPU Skinning ve Bone Limiti Zorluğu
Mobil Cihazlarda GPU Skinning Bottleneck Problemi
Skinned skeletal mesh'ler GPU'ya gönderilmeden önce vertex ve bone chunk'larına ayrılır. Her chunk tek bir draw call ile işlenir ve mobil GPU'ların aynı anda skin edebileceği bone matrislerinin sayısı üzerinde katı bir donanım limiti vardır. Bu kısıtlama, vertex shader için kullanılabilir durumda olan uniform vector sayısı ile tanımlanır. Varsayılan bir MetaHuman karakter iskeleti, mobil limitleri kolayca aşan ve rendering hatalarına, vertex tearing sorunlarına veya tamamen GPU kilitlenmelerine yol açan 600'den fazla bone içerir.
Bu donanım kısıtlamasını aşmak için, motoru skeletal mesh chunk'larını hiçbir draw call'un belirli bir bone sayısından fazlasını referans almayacağı şekilde bölmeye zorlamalısınız. Bu, skinning uyumluluk ayarlarını düzenleyerek elde edilir. Eğer bu konfigürasyonu uygulamazsanız, karakter modelleriniz Android ve iOS cihazlarda düzgün bir şekilde skin edilemeyecek, statik veya oldukça bozulmuş mesh'ler gösterecektir.
DefaultEngine.ini Dosyasını Yapılandırmak
Bone skinning limitlerini çözmek için projenizin DefaultEngine.ini konfigürasyon dosyasını değiştirmelisiniz. Bu dosyayı proje dizininizin kökündeki Config klasöründe bulun. [ConsoleVariables] bölümünün altına aşağıdaki satırı ekleyin:
[ConsoleVariables]
Compat.MAX_GPUSKIN_BONES=75
Bu console variable, shader derleyicisine skinning chunk başına maksimum bone sayısını 75 ile sınırlamasını söyler. Bu, eski veya orta segment mobil GPU'lar için katı bir donanım limitidir. Bu değerin daha düşük ayarlanmasının, skeletal mesh derleyicisini mesh'i daha fazla sayıda chunk'a bölmeye zorlayacağını unutmayın. Bu durum rendering uyumluluğunu çözse de, daha fazla chunk daha fazla draw call anlamına gelir; bu da performans bottleneck'ini CPU render thread'inize kaydırabilir.
Bone Sayısını Azaltmak ve Component Stripping
Tam yüz animasyonlarına ihtiyaç duymayan arka plan karakterleri veya NPC'ler için iskeleti sadeleştirmelisiniz. Örneğin; parmakları, ayak parmaklarını ve yüz ifadesi bone'larını kaldırmak, bir karakterin toplam bone sayısını 600'ün üzerinden 75'in altına düşürebilir. Bu, karakter mesh'inin herhangi bir draw call artışı olmadan tek bir chunk olarak render edilmesini sağlar.
Multiplayer oyununuz için dedicated server'lar da kuruyorsanız, istemci tarafı optimizasyonları madalyonun sadece yarısıdır. Sunucu bellek yükünü azaltmak ve CPU performansını optimize etmek için how to master Unreal Engine dedicated server asset stripping konulu adım adım kılavuzumuza göz atın.
MetaHuman Saç Optimizasyonu: Groom Strands vs. Hair Cards
Strand Rendering Maliyeti
Epic'in groom strand rendering teknolojisi, her bir saç telini dinamik olarak çizer. Bu teknoloji üst düzey masaüstü GPU'larda son derece detaylı saçlar üretse de inanılmaz derecede maliyetlidir. Strand rendering, derinlik sıralaması (depth sorting) ve shadow map üretimi için compute shader geçişlerine dayanır ve bu da önemli ölçüde piksel doldurma hızı (pixel fill rate) ve bellek bant genişliği tüketir.
Mobil cihazlarda strand rendering ya tamamen desteklenmez ya da kabul edilemez bir maliyetle çalışır—genellikle sadece tek bir karakterin saçı için 15 ms'nin üzerinde GPU süresi tüketir. Mobil GPU'lar, kare başına yüz binlerce bağımsız saç telini sıralamak ve gölgelendirmek (shade) için gereken saf bellek bant genişliğinden yoksundur.
Hair Cards Uygulaması
Çözüm, strand tabanlı groom'ları hair cards ile değiştirmektir. Hair cards, saçları önceden render edilmiş saç dokuları ile kaplanmış düz, basitleştirilmiş poligon mesh'ler kullanarak temsil eder. Bu yaklaşım, mobil forward render path ile son derece uyumludur.
Hair cards uygulamak için MetaHuman Creator'ı açın ve karakteriniz için card tabanlı groom LOD'ları ürettiğinizden emin olun. Strand tabanlı saçları card tabanlı groom'larla değiştirmek, tek bir karakterin saçı için rendering süresini Apple A15 veya Snapdragon 8 Gen 1 gibi modern bir mobil çipte yaklaşık 18.2 ms'den 0.9 ms'ye düşürür. Bu devasa tasarruf, rendering bütçenizi oynanış öğelerine veya çevre detaylarına ayırmanıza olanak tanır.
Post-Process Anim Blueprint'lerini Devre Dışı Bırakmak
MetaHuman'lar; ikincil bone hareketlerini, düzeltici kas şekillerini ve eklem dinamiklerini yönlendirmek için post-process animation blueprint'lerini kullanır. Bu durum PC'de gerçekçi cilt hareketleri eklese de, her karede CPU üzerinde karmaşık skeletal hesaplamalar çalıştırır. Mobil cihazlarda bu CPU yükü, game thread'i kolayca bottleneck'e sokabilir.
CPU döngülerini geri kazanmak için mobil cihazlarda post-process animation blueprint'ini devre dışı bırakabilirsiniz. Bu işlem, skeletal mesh bileşenlerinde bDisablePostProcessAnims = true ayarlanarak yapılır. Bu post-process'leri devre dışı bırakmak, standart mobil donanımlarda 4.5 ms'ye kadar CPU kare süresi tasarrufu sağlar.
Mobil Ortamlar için PCG Optimizasyonu
Çalışma Zamanında (Runtime) PCG Çalıştırmanın Getirdiği Yük
Procedural Content Generation (PCG) framework'ü, kurallara ve volume'lara bağlı olarak static mesh, foliage ve actor'leri dağıtarak ortamlarınızı dinamik bir şekilde doldurmanıza olanak tanır. Ancak, mobil CPU'larda runtime'da PCG graph'larını çalıştırmak ciddi performans takılmalarına (hitch) neden olur. Tipik bir runtime graph oluşturma işlemi, bölüm yükleme (level loading) veya oyuncu spawn etme sırasında game thread'i 1.5 ila 3 saniye boyunca dondurabilir.
Bir multiplayer oyunda bu tür bir takılma tehlikelidir; paket kaybına yol açabilir ve client-server durum desenkronizasyonunu tetikleyebilir. Yüksek performansı korumak için, PCG graph'larınızı editor içerisinde önceden bake etmelisiniz (pre-bake). Bu işlem, oyununuzu paketlemeden önce prosedürel instance'ları statik geometriye dönüştürür.
Adım Adım PCG Baking İş Akışı
- PCG Volume Seçin: Unreal Editor viewport'unda, ortam öğelerinizi içeren PCG volume'u seçin.
- Generate ve İnceleyin: Volume'un detaylar panelinde, asset'lerinizin prosedürel yerleşimini önizlemek için Generate seçeneğine tıklayın.
- Export to Actor: PCG araçları (utilities) menüsünde Export to Actor seçeneğini bulun.
- Instanced Mesh Seçimi: Hedef format olarak Hierarchical Instanced Static Mesh (HISM) seçin. Bu instance grubu, tüm özdeş mesh'leri tek bir GPU draw call ile çizdiğinden mobil GPU'lar için son derece optimize edilmiştir.
- Graph'ı Temizleyin: Export işleminden sonra, PCG volume'un generation tetikleyicisini Editor Only olarak ayarlayın veya volume'u temizleyin. Bu, runtime motorunun graph'ı yeniden oluşturmaya çalışmasını engeller.
Dinamik HISM Culling ve Streaming
PCG instance'larınızı HISM'lere bake ettikten sonra, bunların culling mesafelerini yapılandırmalısınız. HISM'ler instance başına culling'i destekler, yani kameradan belirli bir mesafenin ötesindeki instance'lar çizilmez. HISM bileşenlerinizin detaylar panelinde Start Cull Distance ve End Cull Distance değerlerini ayarlayın. Mobil cihazlar için, toplam görünür poligon sayısını mobil GPU bütçesi dahilinde tutmak amacıyla 5000 ila 8000 birimlik bir cull distance önerilir.
Üretim Sürümü C++ Optimizasyon Script'i
Bu optimizasyonları runtime'da otomatikleştirmek için özel bir yardımcı sınıf yazabilirsiniz. Aşağıdaki C++ kodu; hedef platformu kontrol etmeyi, programatik olarak düşük LOD'ları zorlamayı, post-process animation blueprint'lerini devre dışı bırakmayı ve bir mobil cihazda MetaHuman spawn ederken groom bileşenlerini card tabanlı rendering kullanmaya zorlamayı gösterir. Bunu UMetaHumanMobileOptimizer gibi bir sınıfta uygulayabilirsiniz:
#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
}
};
Bu yardımcı fonksiyon, karakterinizin BeginPlay event'inden veya bir MetaHuman actor'ünü spawn ettikten hemen sonra çağrılabilir. Koşullu derleme makroları (PLATFORM_ANDROID || PLATFORM_IOS) kullanılarak, derleyici bu geçersiz kılmaları (override) PC ve konsol derlemelerinden temizler, böylece platformlar arası görsel doğruluğu otomatik olarak korumanıza olanak tanır.
Substrate Materyallerini Mobil GPU'lar için Uyarlamak
Substrate Nedir?
Substrate, geleneksel Unreal Engine shading modelini modüler, çok katmanlı bir materyal framework'ü ile değiştirir. Substrate, geliştiricilerin birden fazla shading slab'ini üst üste yığmasına olanak tanır (örneğin, pürüzlü bir metal katmanın üzerine doğrudan parlak bir clear coat katmanı yerleştirmek gibi). Substrate, üst düzey sinematik asset'ler için mükemmel olsa da mobil renderer'lar için ciddi bir performans engeli oluşturur.
Mobil GPU'lar, GPU çekirdeği ile yonga üzerindeki (on-chip) frame buffer arasındaki bellek veriyolunun (memory bus) ana bottleneck olduğu tiled rendering mimarilerine büyük ölçüde dayanır. Karmaşık Substrate materyalleri, frame buffer'a yazılan piksel başına bayt (BPP) miktarını artırarak termal throttling'e ve kare hızı düşüşlerine neden olur.
Materyal Karmaşıklığını Quality Level Switch'ler ile Yönetmek
Substrate materyallerini mobilde performanslı tutmak için Material Editor içindeki Material Quality Level Switch ve Feature Level Switch node'larını kullanmalısınız. Bu node'lar, hedef platforma bağlı olarak materyal graph'ını basitleştirmenize olanak tanır.
Mobil platformlar için, çok katmanlı Substrate blend'lerini devre dışı bırakarak graph'ı basitleştirin. Bunun yerine, asset'inizin görsel stiline yaklaşan tek bir slab yapısına geri dönün (fall back). Materyal node'larınızı bir quality switch üzerinden yönlendirerek, yazma bant genişliğini piksel başına 32 bayttan standart 8 bayta düşürebilir, böylece daha az ısınan bir cihaz ve kararlı kare hızları elde edebilirsiniz.
Mobil Optimizasyon İçin Uygulanabilir 5 En İyi Pratik
- Tüm PCG graph'larını HISM'lere pre-bake edin: PCG graph'larını runtime'da client üzerinde çalıştırmayın. Editor geliştirmesi sırasında graph'ları Hierarchical Instanced Static Meshes (HISMs) olarak pre-bake edin ve uygun start/end cull mesafelerini yapılandırın.
- Bone sayılarını küresel olarak sınırlayın: Skeletal mesh'lerin buffer overflow'ları tetiklemeden mobil GPU'larda doğru şekilde render edilmesini sağlamak için projenizin DefaultEngine.ini dosyasına
Compat.MAX_GPUSKIN_BONES=75satırını ekleyin. - Sadece card tabanlı groom'ları kullanın: Mobil profiller için strand tabanlı groom'ları devre dışı bırakın. Card tabanlı saç rendering'i, karakter başına GPU kare sürelerini 18 ms'den 1 ms'nin altına indirir.
- Material Quality Switch'lerden Yararlanın: Mobil platformlarda karmaşık shading katmanlarını tek bir slab'e basitleştirmek ve GPU bant genişliğini azaltmak için Substrate materyallerinizde Material Quality Level Switch node'unu uygulayın.
- Post-process animation blueprint'lerini devre dışı bırakın: Game thread üzerindeki değerli CPU döngülerini geri kazanmak için mobil cihazlarda karakterinizin skeletal component'lerinde
bDisablePostProcessAnims = trueolarak ayarlayın.
Multiplayer ve Backend Denklemi
Rendering'in Ötesi: Mobil Ağ Optimizasyonu
Cross-platform multiplayer oyunlar geliştirirken, client tarafı optimizasyonları denklemin sadece bir parçasıdır. Mobil cihazlar sıklıkla hücresel veri (5G/4G) ile Wi-Fi arasında geçiş yaparak ağ dalgalanmaları yaşar. Bu dalgalanmalar paket kaybına (packet loss), jitter'a ve yüksek gecikme (latency) dalgalanmalarına yol açar.
Eğer ağ senkronizasyon kodunuz sağlam (robust) değilse, bu gecikme dalgalanmaları actor replication'ının senkronizasyondan çıkıp dünya durumunu (world state) bozduğu the Unreal Engine multiplayer sync bug hatasını tetikleyebilir. Mobil ağ kısıtlamaları altında multiplayer durumlarını yönetmek; esnek ağ sürücüleri, delta compression ve server-authoritative reconciliation gerektiren karmaşık bir problemdir.
horizOn ile Altyapı Yükünü Hafifletmek
Kendi başınıza esnek bir multiplayer backend oluşturmak ve sürdürmek devasa bir mühendislik çabasıdır. Load balancer'lar kurmanız, küresel veritabanı replikasyonunu yönetmeniz, matchmaking mantığını uygulamanız ve mobil faturalandırmayı halletmeniz gerekir. Bu altyapı çalışması aylar süren bir geliştirme süresi alabilir ve sürekli bakım gerektirir.
horizOn ile bu backend servisleri önceden yapılandırılmış olarak gelir. horizOn, oyun geliştiricilerine oturum matchmaking, düşük gecikmeli durum senkronizasyonu (state synchronization), veritabanı persistence ve platformlar arası kimlik doğrulama (authentication) özelliklerini hazır olarak sunar. Bu sayede, sunucu kümelerini (server clusters) ve veritabanı ölçeklenebilirliğini yönetmek yerine client'larınızı optimize etmeye ve oyun döngünüzü cilalamaya odaklanabilirsiniz.
Sonuç ve Sonraki Adımlar
MetaHumans ve PCG gibi yeni nesil özellikleri mobil için optimize etmek; rendering bütçeleri, skeletal mesh derlemesi ve materyal shading karmaşıklığı üzerinde sıkı bir kontrol gerektirir. Prosedürel asset'lerinizi pre-bake ederek, bone sayısı limitlerini sınırlayarak ve card tabanlı saç rendering kullanarak, el cihazlarında yüksek kaliteli platformlar arası deneyimler sunabilirsiniz.
Multiplayer backend'inizi ölçeklendirmeye hazır mısınız? Altyapınızı nasıl basitleştirebileceğinizi ve oyuncularınızı PC, konsol ve mobil genelinde nasıl senkronize tutabileceğinizi görmek için horizOn'u ücretsiz deneyin veya API docs sayfasına göz atın.
Kaynak: Tutorial: Optimizing Next Gen Features for Mobile Game Development