Unreal Engine モバイル最適化: MetaHumansとPCGを60 FPSで動作させる
要点まとめ
Unreal Engineを用いたモバイル開発において、MetaHumansやPCGなどの次世代機能を60 FPSで動作させるための最適化手法を解説しています。GPUボーンスキニング制限の回避、Groom StrandsからHair Cardsへの置き換え、およびPCGグラフのHISMへの事前ベイクといった具体的なワークフローを解説します。さらに、モバイル特有のネットワーク変動への対策として、MultiplayerのBackend構築を効率化するhorizOnの活用についても紹介しています。
モバイルの障壁:次世代ビジュアルのモバイル展開
開発用PCでは完璧な120 FPSで動作していた美しいプロジェクトも、モバイルパッケージをテストした瞬間にフレームレートは一桁に落ち込み、ターゲットとなるスマートフォンは熱を帯び、GPUはスキニングバッファのオーバーフローでクラッシュしてしまいます。MetaHumans、Procedural Content Generation (PCG)、Substrateマテリアルといったハイエンド機能は、PCやコンソールでは美しく見えますが、モバイルデバイスに過大な負荷をかけることで悪名高い機能です。モバイルのGPUやCPUは、メモリ帯域幅が極めて貴重なリソースとなる、高度に制限された熱および電力枠の中で動作しています。これらの次世代機能をモバイル展開向けに適応させることは、単に設定のチェックボックスをオンにするだけのことではありません。ボーンスキニングの制限、groom構造、プロシージャルなベイク処理のワークフロー、マテリアルのシェーディングの複雑さに対する、深く体系的な理解が必要です。
GPUスキニングとボーン制限の課題
モバイルにおけるGPUスキニングのボトルネック
スキニングされたスケルタルメッシュは、GPUに送られる前に頂点とボーンのチャンクに分割されます。各チャンクは単一のドローコールで処理されますが、モバイルGPUには、同時にスキニングできるボーンマトリクスの数に厳格なハードウェア制限があります。この制限は、頂点シェーダーで利用可能なユニフォームベクトルの数によって定義されます。デフォルトのMetaHumanキャラクターのスケルトンには600以上のボーンが含まれており、モバイルの制限を容易に超えてしまうため、描画エラーや頂点の引き裂き、あるいは完全にGPUがハングアップする原因となります。
このハードウェア制約を回避するには、単一のドローコールが特定の数を超えるボーンを参照しないように、エンジンにスケルタルメッシュのチャンクを強制的に分割させる必要があります。これは、スキニングの互換性設定を調整することで実現できます。この設定を適用しない場合、キャラクターモデルはAndroidやiOSデバイス上で正しくスキニングされず、静止した状態になったり、メッシュが著しく歪んだりします。
DefaultEngine.iniの設定
ボーンスキニングの制限を解決するには、プロジェクトの DefaultEngine.ini 設定ファイルを変更する必要があります。このファイルは、プロジェクトのルートにある Config フォルダ内にあります。[ConsoleVariables] セクションの下に、以下の行を追加します。
[ConsoleVariables]
Compat.MAX_GPUSKIN_BONES=75
このコンソール変数は、スキニングチャンクあたりの最大ボーン数を75にクランプするようシェーダーコンパイラに指示します。これは、旧世代またはミドルレンジのモバイルGPUにおける厳格なハードウェア制限です。この値を低く設定すると、スケルタルメッシュコンパイラに対してメッシュをより多くのチャンクに分割することを強制することになる点に注意してください。これにより描画の互換性は解決されますが、チャンクが増えることはドローコールの増加を意味し、パフォーマンスのボトルネックがCPUのレンダースレッドにシフトする可能性があります。
ボーン数の削減とコンポーネントのストリップ
完全な表情のアーティキュレーション(可動)を必要としない背景キャラクターやノンプレイヤーキャラクター(NPC)については、スケルトンを削ぎ落とす(ストリップする)必要があります。例えば、指、つま先、表情ボーンを削除することで、キャラクターの総ボーン数を600以上から75未満に削減できます。これにより、キャラクターメッシュをドローコールを増やすことなく単一のチャンクとしてレンダリングできるようになります。
マルチプレイヤーゲーム向けに Dedicated Server をデプロイしている場合、クライアント側の最適化は半分にすぎません。レンダリングアセットを完全にストリップすることで、サーバー側のパフォーマンスも最適化する必要があります。サーバーのメモリオーバーヘッドを削減し、CPUパフォーマンスを最適化するためのアセットストリップ手順については、ステップバイステップガイド how to master Unreal Engine dedicated server asset stripping をご覧ください。
MetaHumanの髪の最適化:Groom Strands vs. Hair Cards
Strandレンダリングのコスト
Epicのgroom strandレンダリング技術は、個々の髪のカーブを動的に描画します。これにより、ハイエンドのデスクトップGPUでは非常に詳細な髪の毛が表現されますが、引き換えにコストが非常に高くなります。Strandレンダリングは、深度ソートとシャドウマップ生成のためにコンピュートシェーダーパスに依存しており、大量のピクセルフィルレートとメモリ帯域幅を消費します。
モバイルデバイスでは、strandレンダリングは完全にサポートされていないか、許容できないほど高いコスト(多くの場合、キャラクター1人の髪の毛だけで15ms以上のGPU時間を消費)で動作します。モバイルGPUには、フレームごとに数十万もの個々の髪のカーブをソートし、シェーディングするのに必要な生のメモリ帯域幅が不足しています。
Hair Cardsの実装
解決策は、strandベースのgroomをhair cardsに置き換えることです。Hair cardsは、事前レンダリングされた髪のテクスチャをマッピングした、平坦で簡素化されたポリゴンメッシュを使用して髪を表現します。このアプローチは、モバイルのフォワードレンダーパスと非常に高い互換性があります。
Hair cardsを実装するには、MetaHuman Creatorを開き、キャラクター用にカードベースのgroom LODを生成するようにしてください。Strandベースの髪をカードベース of groomに置き換えることで、Apple A15やSnapdragon 8 Gen 1などの現代的なモバイルチップにおいて、キャラクター1人の髪のレンダリング時間が約18.2msから0.9msに短縮されます。この大幅な節約により、レンダリングバジェットをゲームプレイ要素や環境のディテールに割り当てることができます。
ポストプロセスアニメーションブループリントの無効化
MetaHumansは、二次的なボーンの動き、補正用筋肉形状、および関節のダイナミクスを制御するために、ポストプロセスアニメーションブループリントを使用しています。これによりPC上ではリアルな皮膚の動きが追加されますが、CPU上で毎フレーム複雑なスケルタル計算が実行されます。モバイルでは、このCPUオーバーヘッドによってゲームスレッドが容易にボトルネックになります。
モバイルデバイスでは、ポストプロセスアニメーションブループリントを無効にしてCPUサイクルを回収できます。これは、スケルタルメッシュコンポーネントで bDisablePostProcessAnims = true を設定することで行います。これらのポストプロセスを無効にすることで、標準的なモバイルハードウェア上で最大4.5msのCPUフレーム時間を節約できます。
モバイル環境向けPCGの最適化
実行時におけるPCG実行のオーバーヘッド
Procedural Content Generation (PCG) フレームワークを使用すると、ルールやボリュームに基づいてスタティックメッシュ、フォリッジ、アクターを散布し、環境を動的に構築できます。しかし、モバイルCPU上で実行時にPCGグラフを実行すると、深刻なパフォーマンスの引っかかり(ヒッチ)が発生します。典型的な実行時グラフ生成では、レベルのロード中やプレイヤーのスポーン中にゲームスレッドが1.5〜3秒間フリーズすることがあります。
Multiplayerゲームにおいて、このようなヒッチは危険です。パケットロスの原因となり、クライアントとサーバー間の状態の同期ズレ(デシンク)を引き起こす可能性があります。高いパフォーマンスを維持するには、エディタ内でPCGグラフを事前にベイクしておく必要があります。これにより、ゲームをパッケージングする前に、プロシージャルなインスタンスがスタティックなジオメトリに変換されます。
PCGベイクのステップバイステップワークフロー
- Select the PCG Volume: Unreal Editorのビューポートで、環境要素を含むPCGボリュームを選択します。
- Generate and Inspect: ボリュームの詳細パネルで Generate をクリックし、アセットのプロシージャルな配置をプレビューします。
- Export to Actor: PCGユーティリティメニュー内の Export to Actor オプションを見つけます。
- Choose Instanced Meshes: ターゲット形式として Hierarchical Instanced Static Mesh (HISM) を選択します。このインスタンスグループは、すべての同一メッシュを単一のGPUドローコールで描画するため、モバイルGPU向けに高度に最適化されています。
- Clear the Graph: エクスポート後、PCGボリュームの生成トリガーを Editor Only に設定するか、ボリュームをクリアします。これにより、実行時のエンジンがグラフを再作成しようとするのを防ぎます。
動的なHISMのカリングとストリーミング
PCGインスタンスをHISMにベイクした後は、カリング距離を設定する必要があります。HISMはインスタンスごとのカリングをサポートしており、カメラから一定の距離を超えたインスタンスは描画されません。HISMコンポーネントの詳細パネルで Start Cull Distance と End Cull Distance を設定します。モバイルの場合、表示される総ポリゴン数をモバイルGPUのバジェット内に収めるために、5000〜8000ユニットのカリング距離を推奨します。
プロダクション用C++最適化スクリプト
実行時にこれらの最適化を自動化するために、カスタムヘルパークラスを作成できます。以下のC++コードは、モバイルデバイス上でMetaHumanをスポーンする際に、ターゲットプラットフォームをチェックし、プログラムで強制的に低いLODを適用し、ポストプロセスアニメーションブループリントを無効化し、groomコンポーネントにカードベースのレンダリングを使用させる方法を示しています。これは 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
}
};
このヘルパー関数は、キャラクターの BeginPlay イベントから、またはMetaHumanアクターをスポーンした直後に呼び出すことができます。条件付きコンパイルマクロ(PLATFORM_ANDROID || PLATFORM_IOS)を使用することで、コンパイラはPCやコンソールビルドからこれらのオーバーライドを排除するため、クロスプラットフォームにおけるビジュアルクオリティを自動的に維持できます。
モバイルGPU向けSubstrateマテリアルの適応
Substrateとは?
Substrateは、従来のUnreal Engineのシェーディングモデルに代わる、モジュール式で多層化されたマテリアルフレームワークです。Substrateを使用すると、開発者は複数のシェーディングスラブを重ねることができます(例:粗い金属レイヤーのすぐ上に光沢のあるクリアコートレイヤーを配置するなど)。Substrateはハイエンドのシネマティックアセットには優れていますが、モバイルレンダラーにとっては深刻なパフォーマンスの障害となります。
モバイルGPUはタイル型レンダリング(tiled rendering)アーキテクチャに大きく依存しており、GPUコアとオンチップのフレームバッファ間のメモリバスが主要なボトルネックになります。複雑なSubstrateマテリアルは、フレームバッファに書き込まれるピクセルあたりのバイト数(BPP)を増加させ、サーマルスロットリングやフレームレートの低下を引き起こします。
クオリティレベルスイッチによるマテリアル複雑度の管理
モバイル上でSubstrateマテリアルのパフォーマンスを維持するには、マテリアルエディタ内の Material Quality Level Switch および Feature Level Switch ノードを使用する必要があります。これらのノードを使用すると、ターゲットプラットフォームに基づいてマテリアルグラフを簡素化できます。
モバイルプラットフォーム向けには、多層のSubstrateブレンドをバイパスしてグラフを簡素化します。代わりに、アセットのビジュアルスタイルを近似する単一のスラブにフォールバックさせます。マテリアルノードをクオリティスイッチ経由でルーティングすることにより、書き込み帯域幅をピクセルあたり32バイトから標準的な8バイトに削減でき、デバイスの発熱を抑えて安定したフレームレートを実現できます。
モバイル最適化のための5つの実践的ベストプラクティス
- Pre-bake all PCG graphs into HISMs: 実行時にクライアント上でPCGグラフを実行しないでください。エディタ開発中にグラフをHierarchical Instanced Static Meshes (HISMs)に事前ベイクし、適切な開始/終了カリング距離を設定します。
- Restrict bone counts globally: プロジェクトの DefaultEngine.ini ファイルに
Compat.MAX_GPUSKIN_BONES=75を追加し、バッファオーバーフローを引き起こすことなくモバイルGPUでスケルタルメッシュが正しく描画されるようにします。 - Use card-based grooms exclusively: モバイルプロファイルではstrandベース of groomを無効にします。カードベースの髪のレンダリングは、キャラクター1人あたりのGPUフレーム時間を18msから1ms未満に短縮します。
- Leverage Material Quality Switches: SubstrateマテリアルにMaterial Quality Level Switchノードを実装し、モバイルプラットフォームでは複雑なシェーディングレイヤーを単一のスラブに簡素化して、GPU帯域幅を削減します。
- Disable post-process animation blueprints: モバイルではキャラクターのスケルタルコンポーネントで
bDisablePostProcessAnims = trueを設定し、ゲームスレッド上の貴重なCPUサイクルを回収します。
MultiplayerとBackendの相乗効果
レンダリングの先へ:モバイルネットワークの最適化
クロスプラットフォームの Multiplayer ゲームを開発する場合、クライアント側の最適化は方程式の一部にすぎません。モバイルデバイスは頻繁にネットワークの変動を経験し、モバイルデータ通信(5G/4G)とWi-Fiの間で切り替わります。これらの変動は、パケットロス、ジッター、および高レイテンシのスパイクを引き起こします。
ネットワーク同期コードが堅牢でない場合、これらのレイテンシスパイクによって the Unreal Engine multiplayer sync bug がトリガーされ、アクターのレプリケーションが同期ズレを起こしてワールド状態が破損する可能性があります。モバイルネットワークの制約下で Multiplayer の状態を管理することは、回復力のあるネットワークドライバー、デルタ圧縮、およびサーバー権限による調整(server-authoritative reconciliation)を必要とする複雑な課題です。
horizOnによるインフラ負担の軽減
回復力のある Multiplayer の Backend を自前で構築・維持することは、膨大なエンジニアリング作業を伴います。ロードバランサーのプロビジョニング、グローバルなデータベースレプリケーションの管理、Matchmaking ロジックの実装、モバイル課金の処理などが必要になります。このインフラ作業は、開発に数か月を要し、継続的なメンテナンスが必要となります。
horizOn を使用すれば、これらの Backend サービスは事前に設定された状態で提供されます。horizOn は、セッションの Matchmaking、低レイテンシの状態同期、データベース永続化、およびクロスプラットフォーム認証をすぐに使える状態でゲーム開発者に提供します。これにより、サーバークラスターの管理やデータベースのスケーラビリティに煩わされることなく、クライアントの最適化とゲームループのブラッシュアップに集中できます。
結論と次のステップ
MetaHumansやPCGのような次世代機能をモバイル向けに最適化するには、レンダリングバジェット、スケルタルメッシュのコンパイル、およびマテリアルシェーディングの複雑さを厳格に制御する必要があります。プロシージャルアセットの事前ベイク、ボーン数制限のクランプ、カードベースの髪レンダリングの採用により、モバイルデバイス上で高品質なクロスプラットフォーム体験を提供できます。
Multiplayer の Backend をスケールする準備はできましたか?horizOn を無料でお試しいただくか、API docs をチェックして、インフラを簡素化し、PC、コンソール、モバイル間でプレイヤーを同期させる方法をご確認ください。
Source: Tutorial: Optimizing Next Gen Features for Mobile Game Development