Retour au Blog

Optimisation mobile sous Unreal Engine : faire tourner les MetaHumans et le PCG à 60 FPS

Publié le 19 juin 2026
Optimisation mobile sous Unreal Engine : faire tourner les MetaHumans et le PCG à 60 FPS

En bref

Ce guide technique détaille les méthodes pour optimiser les fonctionnalités next-gen telles que les MetaHumans et le PCG afin d'atteindre les 60 FPS sur mobile avec Unreal Engine. Il explique comment configurer les limites de bone skinning, remplacer le strand rendering par des hair cards et simplifier les matériaux Substrate complexes via des switches de qualité. Enfin, il présente les meilleures pratiques pour le baking des graphes procéduraux et l'intégration d'un backend Multiplayer robuste.

La barrière du mobile : apporter des visuels next-gen sur mobile

Votre superbe projet PC tourne à un parfait 120 FPS sur votre station de travail de développement, mais dès que vous testez le package mobile, le frame rate chute à un seul chiffre, le téléphone cible surchauffe et le GPU crash à cause d'un skinning buffer overflow. Les fonctionnalités haut de gamme comme les MetaHumans, le Procedural Content Generation (PCG) et les matériaux Substrate sont superbes sur PC et consoles, mais elles sont réputées pour mettre les appareils mobiles à genoux. Les GPU et CPU mobiles fonctionnent dans des enveloppes thermiques et de puissance très limitées, où la bande passante mémoire est une ressource critique. Adapter ces fonctionnalités next-gen pour un déploiement mobile ne se résume pas à cocher une case de configuration ; cela nécessite une compréhension approfondie et systématique des limites de bone skinning, des structures de groom, des workflows de baking procédural et de la complexité du shading des matériaux.

Le défi du GPU Skinning et de la limite de bones

Le bottleneck du GPU Skinning sur mobile

Les skeletal meshes avec skinning sont divisés en chunks de vertices et de bones avant d'être envoyés au GPU. Chaque chunk est traité dans un seul draw call, et les GPU mobiles ont une limite matérielle stricte sur le nombre de matrices de bones qu'ils peuvent traiter simultanément par skinning. Cette limitation est définie par le nombre de uniform vectors disponibles pour le vertex shader. Le squelette par défaut d'un personnage MetaHuman contient plus de 600 bones, ce qui dépasse largement les limites mobiles et entraîne des erreurs de rendu, du vertex tearing ou des plantages complets du GPU.

Pour contourner cette contrainte matérielle, vous devez forcer le moteur à partitionner les chunks de skeletal meshes de manière à ce qu'aucun draw call ne fasse référence à plus d'un certain nombre de bones. Cela s'effectue en ajustant les paramètres de compatibilité de skinning. Si vous n'appliquez pas cette configuration, le skinning de vos modèles de personnages ne s'effectuera pas correctement sur les appareils Android et iOS, affichant des meshes statiques ou fortement déformés.

Configurer le DefaultEngine.ini

Pour résoudre les limites de bone skinning, vous devez modifier le fichier de configuration DefaultEngine.ini de votre projet. Localisez ce fichier dans le dossier Config à la racine de votre projet. Sous la section [ConsoleVariables], ajoutez la ligne suivante :

[ConsoleVariables]
Compat.MAX_GPUSKIN_BONES=75

Cette console variable indique au shader compiler de limiter le nombre maximum de bones par chunk de skinning à 75. Il s'agit d'une limite matérielle stricte pour les GPU mobiles plus anciens ou de milieu de gamme. Gardez à l'esprit qu'une valeur plus basse force le compilateur de skeletal meshes à diviser le mesh en un plus grand nombre de chunks. Bien que cela résolve la compatibilité du rendu, un plus grand nombre de chunks se traduit par plus de draw calls, ce qui peut déplacer le bottleneck de performance vers le thread de rendu CPU.

Réduction du nombre de bones et suppression de composants

Pour les personnages en arrière-plan ou les personnages non-joueurs (NPC) qui ne nécessitent pas une articulation faciale complète, vous devriez simplifier le squelette. Par exemple, retirer les doigts, les orteils et les bones d'expression faciale peut réduire le nombre total de bones d'un personnage de plus de 600 à moins de 75. Cela permet au mesh du personnage d'être rendu sous la forme d'un seul chunk sans inflation du nombre de draw calls.

Si vous déployez également des Dedicated Server pour votre jeu Multiplayer, les optimisations côté client ne représentent que la moitié du travail. Vous devrez aussi optimiser les performances côté serveur en supprimant entièrement les assets de rendu. Consultez notre guide étape par étape sur comment maîtriser l'asset stripping pour Dedicated Server sous Unreal Engine afin de réduire l'empreinte mémoire du serveur et d'optimiser les performances CPU.

Optimiser les cheveux MetaHuman : Groom Strands vs. Hair Cards

Le coût du Strand Rendering

La technologie de rendu de groom par strands d'Epic dessine dynamiquement chaque courbe de cheveu individuelle. Bien que cela produise des cheveux extrêmement détaillés sur les GPU de bureau haut de gamme, c'est incroyablement coûteux. Le strand rendering repose sur des passes de compute shader pour le tri en profondeur et la génération de shadow maps, ce qui consomme une part substantielle du pixel fill rate et de la bande passante mémoire.

Sur les appareils mobiles, le strand rendering est soit totalement non supporté, soit s'exécute à un coût inacceptable — consommant souvent plus de 15 ms de temps GPU uniquement pour les cheveux d'un seul personnage. Les GPU mobiles manquent de la bande passante mémoire brute nécessaire pour trier et shader des centaines de milliers de courbes de cheveux individuelles par frame.

Implémenter des Hair Cards

La solution consiste à remplacer les grooms basés sur des strands par des hair cards. Les hair cards représentent les cheveux à l'aide de polygones plats et simplifiés, associés à des textures de cheveux pré-rendues. Cette approche est parfaitement compatible avec la forward render path mobile.

Pour implémenter les hair cards, ouvrez le MetaHuman Creator et assurez-vous de générer les LOD de groom basés sur des cards pour votre personnage. Remplacer les cheveux basés sur des strands par des grooms basés sur des cards réduit le temps de rendu des cheveux d'un seul personnage d'environ 18,2 ms à 0,9 ms sur une puce mobile moderne telle que l'Apple A15 ou le Snapdragon 8 Gen 1. Cette économie massive vous permet d'allouer vos budgets de rendu à des éléments de gameplay ou aux détails de l'environnement.

Désactiver les Post-Process Anim Blueprints

Les MetaHumans utilisent des post-process animation blueprints pour gérer les mouvements secondaires des bones, les formes musculaires correctives et la dynamique des articulations. Bien que cela ajoute un mouvement de peau réaliste sur PC, cela exécute des calculs squelettiques complexes sur le CPU à chaque frame. Sur mobile, cet overhead CPU peut facilement créer un bottleneck sur le game thread.

Vous pouvez désactiver le post-process animation blueprint sur les appareils mobiles pour récupérer des cycles CPU. Cela se fait en définissant bDisablePostProcessAnims = true sur les composants de skeletal mesh. Désactiver ces post-processus permet d'économiser jusqu'à 4,5 ms de temps de frame CPU sur du matériel mobile standard.

Optimiser le PCG pour les environnements mobiles

L'overhead de l'exécution du PCG au runtime

Le framework Procedural Content Generation (PCG) vous permet de peupler vos environnements de manière dynamique en répartissant des static meshes, du foliage et des actors en fonction de règles et de volumes. Cependant, l'exécution de graphes PCG au runtime sur des CPU mobiles provoque de graves saccades de performance (hitches). La génération d'un graphe classique au runtime peut figer le game thread pendant 1,5 à 3 secondes lors du chargement des niveaux ou du spawn des joueurs.

Dans un jeu Multiplayer, un tel ralentissement (hitch) est dangereux ; il peut entraîner des pertes de paquets et déclencher une désynchronisation de l'état client-serveur. Pour maintenir des performances élevées, vous devez pré-bake vos graphes PCG dans l'editor. Cela convertit les instances procédurales en géométrie statique avant de packager votre jeu.

Workflow pas à pas pour le baking du PCG

  1. Sélectionner le volume PCG : Dans le viewport de l'Unreal Editor, sélectionnez le volume PCG contenant vos éléments d'environnement.
  2. Générer et inspecter : Dans le panneau de détails du volume, cliquez sur Generate pour prévisualiser le placement procédural de vos assets.
  3. Exporter vers l'Actor : Recherchez l'option Export to Actor dans le menu des utilitaires PCG.
  4. Choisir les meshes instanciés : Sélectionnez Hierarchical Instanced Static Mesh (HISM) comme format cible. Ce groupe d'instances est hautement optimisé pour les GPU mobiles, car il dessine tous les meshes identiques en un seul draw call GPU.
  5. Nettoyer le graphe : Après l'exportation, configurez le déclencheur de génération du volume PCG sur Editor Only ou videz le volume. Cela empêche le moteur au runtime de tenter de recréer le graphe.

Culling dynamique et streaming des HISM

Une fois vos instances PCG pré-bakées dans des HISM, vous devez configurer leurs distances de culling. Les HISM prennent en charge le culling par instance, ce qui signifie que les instances situées au-delà d'une certaine distance de la caméra ne seront pas dessinées. Définissez la Start Cull Distance et la End Cull Distance dans le panneau de détails de vos composants HISM. Sur mobile, une distance de culling de 5000 à 8000 unités est recommandée afin de maintenir le nombre total de polygones visibles dans les limites du budget du GPU mobile.

Script d'optimisation C++ pour la production

Pour automatiser ces optimisations au runtime, vous pouvez écrire une classe utilitaire personnalisée. Le code C++ suivant montre comment vérifier la plateforme cible, forcer par programmation des LOD bas, désactiver les post-process animation blueprints, et forcer les composants de groom à utiliser le rendu par cards lors du spawn d'un MetaHuman sur un appareil mobile. Vous pouvez implémenter cela dans une classe comme 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
    }
};

Cette fonction utilitaire peut être appelée depuis l'événement BeginPlay de votre personnage ou immédiatement après avoir fait spawner un actor MetaHuman. En utilisant des macros de compilation conditionnelle (PLATFORM_ANDROID || PLATFORM_IOS), le compilateur supprime ces surcharges des builds PC et consoles, vous permettant de maintenir automatiquement la fidélité visuelle multiplateforme.

Adapting Substrate Materials for Mobile GPUs

Qu'est-ce que Substrate ?

Substrate remplace le shading model traditionnel d'Unreal Engine par un framework de matériaux modulaire et multicouche. Substrate permet aux développeurs d'empiler plusieurs slabs de shading (par exemple, placer une couche de clear coat brillant directement sur une couche de métal rugueux). Bien que Substrate soit excellent pour les assets cinématiques haut de gamme, il représente un sérieux obstacle en termes de performances pour les moteurs de rendu mobiles.

Les GPU mobiles s'appuient fortement sur des architectures de rendu par tuiles (tiled rendering) où le bus mémoire entre le cœur du GPU et le frame buffer intégré à la puce est un bottleneck majeur. Les matériaux Substrate complexes augmentent le nombre d'octets par pixel (BPP) écrits dans le frame buffer, provoquant du thermal throttling et des chutes de frame rate.

Gérer la complexité des matériaux via les Quality Level Switches

Pour que les matériaux Substrate restent performants sur mobile, vous devez utiliser les nœuds Material Quality Level Switch et Feature Level Switch dans le Material Editor. Ces nœuds vous permettent de simplifier le graphe de rendu de vos matériaux en fonction de la plateforme cible.

Pour les plateformes mobiles, simplifiez le graphe en contournant les mélanges de couches Substrate complexes. À la place, utilisez un seul slab qui reproduit approximativement le style visuel de votre asset. En faisant passer vos nœuds de matériaux par un switch de qualité, vous pouvez réduire la bande passante d'écriture de 32 octets par pixel à un standard de 8 octets par pixel, ce qui permet à l'appareil de moins chauffer et de maintenir des frame rates stables.

5 bonnes pratiques concrètes pour l'optimisation mobile

  1. Pré-bake tous les graphes PCG dans des HISM : N'exécutez pas de graphes PCG sur le client au runtime. Pré-bakez les graphes dans des Hierarchical Instanced Static Meshes (HISM) pendant le développement dans l'editor et configurez des distances de culling (start/end) appropriées.
  2. Restreindre globalement le nombre de bones : Ajoutez Compat.MAX_GPUSKIN_BONES=75 au fichier DefaultEngine.ini de votre projet pour garantir que les skeletal meshes s'affichent correctement sur les GPU mobiles sans provoquer de buffer overflow.
  3. Utiliser exclusivement des card-based grooms : Désactivez les grooms basés sur des strands pour les profils mobiles. Le rendu de cheveux basé sur des cards réduit les temps de frame GPU de 18 ms à moins de 1 ms par personnage.
  4. Tirer parti des Material Quality Switches : Implémentez le nœud Material Quality Level Switch dans vos matériaux Substrate pour simplifier les couches de shading complexes en un seul slab sur les plateformes mobiles, réduisant ainsi la bande passante GPU.
  5. Désactiver les post-process animation blueprints : Définissez bDisablePostProcessAnims = true sur les composants de skeletal mesh de vos personnages sur mobile pour récupérer de précieux cycles CPU sur le game thread.

L'équation du Multiplayer et du Backend

Au-delà du rendu : l'optimisation réseau sur mobile

Lors du développement de jeux Multiplayer cross-platform, les optimisations côté client ne représentent qu'une partie de l'équation. Les appareils mobiles subissent fréquemment des fluctuations réseau, basculant entre les données cellulaires (5G/4G) et le Wi-Fi. Ces fluctuations introduisent des pertes de paquets, du jitter et de forts pics de latence.

Si votre code de synchronisation réseau n'est pas robuste, ces pics de latence peuvent déclencher le bug de synchronisation Multiplayer d'Unreal Engine, où la réplication des actors se désynchronise et corrompt l'état du monde. Gérer les états Multiplayer sous les contraintes du réseau mobile est un problème complexe qui requiert des drivers réseau résilients, de la compression delta et une réconciliation faisant autorité côté serveur (server-authoritative).

Déléguer l'infrastructure grâce à horizOn

Construire et maintenir soi-même un Backend Multiplayer résilient représente un effort d'ingénierie colossal. Vous devriez provisionner des load balancers, gérer la réplication globale de bases de données, implémenter une logique de Matchmaking et gérer la facturation mobile. Ce travail d'infrastructure peut prendre des mois de développement et nécessite une maintenance continue.

Avec horizOn, ces services de Backend sont préconfigurés. horizOn fournit aux développeurs de jeux du Matchmaking de session, de la synchronisation d'état à faible latence, de la persistance de base de données et de l'authentification cross-platform prêtes à l'emploi. Cela vous permet de vous concentrer sur l'optimisation de vos clients et le peaufinage de votre boucle de jeu, plutôt que de gérer des clusters de serveurs et la scalabilité de bases de données.

Conclusion et prochaines étapes

L'optimisation de fonctionnalités next-gen telles que les MetaHumans et le PCG pour le mobile requiert un contrôle strict du budget de rendu, de la compilation des skeletal meshes et de la complexité du shading des matériaux. En pré-bakant vos assets procéduraux, en limitant le nombre de bones et en utilisant le rendu de cheveux basé sur des cards, vous pouvez proposer des expériences cross-platform de haute fidélité sur les appareils mobiles.

Prêt à scaler votre Backend Multiplayer ? Essayez horizOn gratuitement ou consultez les API docs pour découvrir comment simplifier votre infrastructure et garder vos joueurs synchronisés sur PC, console et mobile.


Source : Tutorial: Optimizing Next Gen Features for Mobile Game Development