Recommandations sur les performances pour Unity

Cet article s’appuie sur les recommandations relatives aux performances pour la réalité mixte, mais il se concentre sur les améliorations propres à Unity.

Nous avons récemment publié une application appelée Quality Fundamentals qui couvre les problèmes courants de performances, de conception et d’environnement, ainsi que les solutions pour les applications HoloLens 2. Cette application est une excellente démo visuelle du contenu qui suit.

Pour optimiser les performances des applications de réalité mixte dans Unity, la première étape, et la plus importante, consiste à utiliser les paramètres d’environnement recommandés pour Unity. Le contenu de cet article s’intéresse à certaines des configurations de scène les plus importantes pour créer des applications Mixed Reality performantes. Certains de ces paramètres recommandés sont également soulignés ci-après.

Comment profiler avec Unity

Unity est fourni avec le profileur intégré Unity Profiler , qui constitue une ressource intéressante pour recueillir de précieux insights sur les performances de votre application. Bien qu’il soit possible d’exécuter le profileur dans l’éditeur, ces métriques ne représentent pas l’environnement d’exécution réel et vous devez donc en utiliser les résultats avec prudence. Nous vous recommandons de profiler à distance votre application pendant son exécution sur un appareil pour obtenir des insights plus précis et exploitables.

Unity fournit une documentation très dense sur les thèmes suivants :

  1. Comment connecter à distance le profileur Unity à des applications UWP
  2. Comment diagnostiquer efficacement les problèmes de performances avec Unity Profiler

Profilage du GPU

Profileur Unity

Une fois Unity Profiler connecté et après avoir ajouté le profileur GPU (consultez Ajouter un profileur dans le coin supérieur droit), vous pouvez voir le temps passé sur le processeur et le GPU respectivement au milieu du profileur. Ainsi, le développeur détermine approximativement et rapidement si son application est liée au processeur ou au GPU.

Processeur et GPU Unity

Notes

Pour utiliser le profilage GPU, vous devez désactiver les travaux graphiques dans les Paramètres de lecteur Unity. Pour plus d’informations, consultez le module de profiler d’utilisation GPU de Unity.

Débogueur de frames Unity

Le débogueur Frame Debugger d’Unity est également un puissant outil d’analyse à votre disposition. Il vous donnera une bonne vue d’ensemble de ce que le GPU effectue chaque frame. Les éléments à rechercher sont des cibles de rendu supplémentaires et des commandes blit pour les copier entre elles, car elles sont très coûteuses sur HoloLens. Dans l’idéal, aucune cible de rendu hors écran ne doit être utilisée sur HoloLens. Celles-ci sont généralement ajoutées lors de l’activation des fonctionnalités de rendu coûteuses (par exemple, MSAA, HDR ou effets plein écran comme la floraison) qui doivent être évités.

Superposition de fréquence d’images HoloLens

La page Performances du système du portail d’appareil contient un bon résumé des performances processeur et GPU de l’appareil. Vous pouvez activer le compteur de fréquence d’images d’affichage dans le casque et afficher le graphique de fréquence d’images dans le casque. Ces options activent respectivement un compteur FPS et un graphique, qui vous donnent des commentaires immédiats dans n’importe quelle application en cours d’exécution sur votre appareil.

PIX

PIX peut également être utilisé pour profiler des applications Unity. Il existe également des instructions détaillées sur l’utilisation et l’installation de PIX pour HoloLens 2. Dans une build de développement, les mêmes étendues que celles que vous voyez dans le débogueur Frame d’Unity s’affichent également dans PIX et peuvent également être inspectées et profilées plus en détail.

Notes

Unity offre la possibilité de modifier facilement la résolution de la cible de rendu de votre application au moment de l’exécution grâce à la propriété XRSettings.renderViewportScale. L’image finale présentée sur l’appareil a une résolution fixe. La plateforme échantillonne la sortie de résolution inférieure pour générer une image de résolution supérieure pour le rendu sur les écrans.

UnityEngine.XR.XRSettings.renderViewportScale = 0.7f;

Recommandations sur les performances de processeur

Le contenu ci-dessous couvre des pratiques liées aux performances de manière plus approfondie, en ciblant particulièrement le développement en C# avec Unity.

Mettre en cache les références

Nous vous recommandons de mettre en cache les références à tous les composants et GameObjects pertinents lors de l’initialisation, car les appels de fonction répétitifs, comme GetComponent<T>() et Camera.main sont plus coûteux en mémoire pour stocker un pointeur. . Camera.main utilise simplement FindGameObjectsWithTag () , qui recherche de façon coûteuse dans votre graphe de scène un objet caméra portant l’étiquette « MainCamera » .

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour
{
    private Camera cam;
    private CustomComponent comp;

    void Start() 
    {
        cam = Camera.main;
        comp = GetComponent<CustomComponent>();
    }

    void Update()
    {
        // Good
        this.transform.position = cam.transform.position + cam.transform.forward * 10.0f;

        // Bad
        this.transform.position = Camera.main.transform.position + Camera.main.transform.forward * 10.0f;

        // Good
        comp.DoSomethingAwesome();

        // Bad
        GetComponent<CustomComponent>().DoSomethingAwesome();
    }
}

Remarque

Éviter GetComponent(string)
Quand vous utilisez GetComponent() , il existe plusieurs surcharges différentes. Il est important de toujours utiliser les implémentations basées sur le type et jamais la surcharge de recherche basée sur la chaîne. Une recherche par chaîne dans votre scène est beaucoup plus coûteuse qu’une recherche par type.
(Correct) Component GetComponent(Type type)
(Correct) T GetComponent<T>()
(Incorrect) Component GetComponent(string)>

Éviter les opérations coûteuses

  1. Éviter l’utilisation de LINQ

    Même si LINQ est très propre et facile à lire et à écrire, cette technologie nécessite généralement plus de calcul et de mémoire que l’écriture manuelle de l’algorithme.

    // Example Code
    using System.Linq;
    
    List<int> data = new List<int>();
    data.Any(x => x > 10);
    
    var result = from x in data
                 where x > 10
                 select x;
    
  2. API Unity courantes

    Certaines API Unity, bien qu’utiles, peuvent s’avérer onéreuses à exécuter. La plupart d’entre elles impliquent la recherche d’une liste de GameObjects correspondante dans l’ensemble de votre graphe de scène. Ces opérations peuvent généralement être évitées en mettant en cache les références ou en implémentant un composant de gestionnaire pour les GameObjects afin de suivre les références au moment de l’exécution.

        GameObject.SendMessage()
        GameObject.BroadcastMessage()
        UnityEngine.Object.Find()
        UnityEngine.Object.FindWithTag()
        UnityEngine.Object.FindObjectOfType()
        UnityEngine.Object.FindObjectsOfType()
        UnityEngine.Object.FindGameObjectsWithTag()
        UnityEngine.Object.FindGameObjectsWithTag()
    

Remarque

SendMessage() et BroadcastMessage() doivent être éliminés à tout prix. Ces fonctions peuvent être de l’ordre de 1 000 fois plus lentes que les appels de fonction directs.

  1. Attention à Boxing

    Boxing est un concept fondamental du langage et runtime C#. Il s’agit du processus qui consiste à wrapper des variables de type valeur, par exemple char, int, bool, etc., dans des variables de type référence. Quand une variable de type valeur fait l’objet d’un « boxing », elle est wrappée dans un System.Object stocké sur le tas managé. De la mémoire est allouée et, quand elle est supprimée, elle doit être traitée par le garbage collector. Ces allocations et désallocations entraînent un coût pour les performances et, dans de nombreux scénarios, s’avèrent inutiles ou peuvent être facilement remplacées par une alternative moins coûteuse.

    Pour éviter le boxing, vérifiez que les variables, les champs et les propriétés dans lesquels vous stockez des types numériques et des structs (notamment Nullable<T>) sont fortement typés en tant que types spécifiques comme int, float? ou MyStruct au lieu d’utiliser l’objet. Si vous placez ces objets dans une liste, veillez à utiliser une liste fortement typée telle que List<int> au lieu de List<object> ou ArrayList.

    Exemple de boxing en C#

    // boolean value type is boxed into object boxedMyVar on the heap
    bool myVar = true;
    object boxedMyVar = myVar;
    

Chemins de code répétitifs

Toutes les fonctions de rappel Unity répétitives (par exemple Update) exécutées un grand nombre de fois par seconde et/ou par trame doivent être écrites avec soin. Toutes les opérations coûteuses ont ici un impact énorme et constant sur les performances.

  1. Fonctions de rappel vides

    Bien que le code ci-dessous puisse vous paraître inoffensif si vous le laissez dans votre application, notamment parce que chaque script Unity s’initialise automatiquement avec une méthode de mise à jour, ces rappels vides peuvent devenir coûteux. Unity fonctionne en alternance entre une limite de code non managé et managé, entre le code UnityEngine et votre code d’application. Le changement de contexte sur ce pont est assez onéreux, même s’il n’y a rien à exécuter. Cela devient particulièrement problématique si votre application comporte des centaines de GameObjects avec des composants qui ont des rappels Unity répétitifs vides.

    void Update()
    {
    }
    

Remarque

Update() est la manifestation la plus courante de ce problème de performances, mais d’autres rappels Unity répétitifs, comme les suivants peuvent s’avérer aussi mauvais, si ce n’est pire : FixedUpdate(), LateUpdate(), OnPostRender", OnPreRender(), OnRenderImage(), etc.

  1. Opérations dont l’exécution une fois par frame est à privilégier

    Les API Unity suivantes sont des opérations courantes pour de nombreuses applications holographiques. Bien que cela ne soit pas toujours possible, les résultats de ces fonctions peuvent être souvent calculés une seule fois et les résultats réutilisés dans l’application pour une image donnée.

    a) Une bonne pratique consiste à avoir une classe ou un service Singleton dédié(e) pour gérer votre Raycast de pointage du regard dans la scène, puis à réutiliser ce résultat dans tous les autres composants de scène, au lieu d’effectuer des opérations Raycast répétées et identiques. Certaines applications peuvent nécessiter des raycasts provenant de différentes origines ou sur différents LayerMasks.

        UnityEngine.Physics.Raycast()
        UnityEngine.Physics.RaycastAll()
    

    b) Évitez les opérations GetComponent() dans les rappels Unity répétés comme Update() en mettant en cache les références dans Start() ou Awake().

        UnityEngine.Object.GetComponent()
    

    c) Une bonne pratique consiste à instancier tous les objets, si possible, lors de l’initialisation et à utiliser la mise en pool d’objets pour recycler et réutiliser les GameObjects tout au long de l’exécution de votre application

        UnityEngine.Object.Instantiate()
    
  2. Éviter les interfaces et les constructions virtuelles

    L’invocation d’appels de fonction par le biais d’interfaces plutôt que d’objets directs ou l’appel de fonctions virtuelles peuvent souvent s’avérer beaucoup plus coûteux que l’utilisation de constructions directes ou d’appels de fonction directs. Si la fonction virtuelle ou interface n’est pas nécessaire, elle doit être supprimée. Toutefois, la baisse de performances dans ces approches est plus intéressante si leur utilisation simplifie la collaboration pour le développement, la lisibilité du code et la maintenabilité du code.

    En règle générale, il est recommandé de ne pas marquer des champs et des fonctions comme virtuels, sauf s’il est clairement attendu que ce membre a besoin d’être remplacé. Une attention particulière doit être portée aux chemins de code à haute fréquence qui sont appelés de nombreuses fois par frame, ou même une seule fois par frame, comme une méthode UpdateUI().

  3. Éviter de passer des structs par valeur

    Contrairement aux classes, les structs sont des types valeur et quand ils sont passés directement à une fonction, leur contenu est copié dans une instance nouvellement créée. Cette copie augmente le coût du processeur, ainsi que la mémoire supplémentaire sur la pile. Pour les petits structs, l’effet est minime et donc acceptable. En revanche, pour les fonctions appelées à plusieurs reprises, chaque frame ainsi que les fonctions acceptant des grands structs, modifiez si possible la définition de fonction pour qu’elle passe par référence. En savoir plus ici

Divers

  1. Physique

    a) En règle générale, le moyen le plus simple d’améliorer la physique consiste à limiter le temps dédié à la physique ou le nombre d’itérations par seconde. La précision de la simulation s’en trouve réduite. Consultez TimeManager dans Unity.

    b) Les types des colliders dans Unity possèdent des caractéristiques de performances très différentes. Les colliders ci-dessous sont listés du plus performant au moins performant, de gauche à droite. Il est important d’éviter les Mesh Colliders, qui sont beaucoup plus onéreux que les colliders primitifs.

    Sphere < Capsule < Box <<< Mesh (Convex) < Mesh (non-Convex)

    Pour plus d’informations, consultez Bonnes pratiques pour la physique dans Unity.

  2. Animations

    Désactivez les animations inactives en désactivant le composant Animator (la désactivation de l’objet jeu n’a pas le même effet). Évitez les modèles de conception où un animateur se trouve dans une boucle qui affecte une valeur à la même chose. Cette technique présente une surcharge considérable, sans effet sur l’application. En savoir plus ici.

  3. Algorithmes complexes

    Si votre application utilise des algorithmes complexes comme des cinématiques inverses, des recherches de chemins, etc., recherchez une approche plus simple ou ajustez les paramètres pertinents pour leurs performances.

Recommandations sur les performances de processeur à GPU

En règle générale, les performances de processeur à GPU diminuent jusqu’aux appels de dessin soumis à la carte graphique. Pour améliorer les performances, les appels de dessin doivent être stratégiquement a) réduits ou b) restructurés afin d’obtenir des résultats optimaux. Étant donné que les appels de dessin eux-mêmes sont gourmands en ressources, leur réduction réduira le travail global nécessaire. De plus, les changements d’état entre les appels de dessin nécessitent des étapes de validation et de traduction coûteuses dans le pilote graphique et par conséquent, la restructuration des appels de dessin de votre application pour limiter les changements d’état (par exemple différents matériaux, etc.) peut accélérer les performances.

Unity dispose d’un excellent article qui donne une vue d’ensemble descriptive du traitement par lot des appels de dessin pour sa plateforme.

Rendu d’instance à passage unique

Le rendu d’instance à passage unique dans Unity permet de réduire les appels de dessin pour chaque œil à un seul appel de dessin instancié. En raison de la cohérence du cache entre deux appels de dessin, les performances sont également améliorées sur le GPU.

Pour activer cette fonctionnalité dans votre projet Unity

  1. Ouvrez OpenXR Settings (accédez à Edit>Project Settings>XR Plugin Management>OpenXR).
  2. Sélectionnez Single Pass Instanced dans le menu déroulant Render Mode.

Lisez les articles suivants sur Unity pour plus d’informations sur l’approche de ce rendu.

Remarque

Un problème courant avec le rendu d’instance à passage unique se produit si les développeurs ont déjà des nuanceurs personnalisés existants non écrits pour l’instanciation. Une fois cette fonctionnalité activée, les développeurs peuvent remarquer que certains GameObjects ne sont rendus que dans un seul œil. Cela est dû au fait que les nuanceurs personnalisés associés n’ont pas les propriétés appropriées pour l’instanciation.

Consultez Single Pass Stereo Rendering for HoloLens sur Unity pour savoir comment résoudre ce problème.

Traitement par lot statique

Unity est capable de traiter par lot de nombreux objets statiques pour réduire les appels de dessin au GPU. Le traitement par lot statique fonctionne pour la plupart des objets Renderer dans Unity qui 1) partagent le même matériau et 2) sont tous marqués comme statiques (sélectionnez un objet dans Unity et cochez la case en haut à droite de l’inspecteur). Les GameObjects marqués comme statiques ne peuvent pas être déplacés dans le runtime de votre application. Ainsi, le traitement par lot statique peut s’avérer difficile à exploiter sur HoloLens, où pratiquement tous les objets ont besoin d’être placés, déplacés, mis à l’échelle, etc. Pour les casques immersifs, le traitement par lot statique peut réduire considérablement les appels de dessin et donc améliorer les performances.

Pour plus d’informations, consultez Traitement par lot statique sous Traitement par lot des appels de dessin dans Unity.

Traitement par lot dynamique

Étant donné qu’il est difficile de marquer des objets comme statiques pour le développement HoloLens, le traitement par lot dynamique peut s’avérer un excellent outil pour compenser cette fonctionnalité manquante. Il peut également s’avérer utile sur les casques immersifs. Toutefois, le traitement par lot dynamique dans Unity peut être difficile à activer car les GameObjects doivent a) partager le même matériau et b) remplir une longue liste d’autres critères.

Lisez Traitement par lot dynamique sous Traitement par lot des appels de dessin dans Unity pour obtenir la liste complète. En règle générale, les GameObjects deviennent non valides pour le traitement par lot dynamique, car les données de maillage associées ne peuvent pas dépasser 300 vertex.

Autres techniques

Le traitement par lot ne peut se produire que si plusieurs GameObjects sont en mesure de partager le même matériau. En règle générale, il est bloqué par la nécessité pour les GameObjects d’avoir une texture unique pour leur matériau respectif. Il est courant de combiner des textures en une seule texture globale, une méthode appelée création d’un atlas de textures.

En outre, il est préférable de combiner les maillages en un seul GameObject, lorsque cela est possible et raisonnable. Chaque convertisseur dans Unity a ses appels de dessin associés au lieu d’envoyer un maillage combiné sous un seul convertisseur.

Remarque

La modification des propriétés de Renderer.material au moment de l’exécution crée une copie du matériau et, par conséquent, interrompt éventuellement le traitement par lot. Utilisez Renderer.sharedMaterial pour modifier les propriétés des matériaux partagés entre les GameObjects.

Recommandations sur les performances de GPU

Découvrez-en plus sur l’optimisation du rendu graphique dans Unity.

Bande passante et taux de remplissage

Pour restituer une trame sur le processeur graphique, une application dépend de la bande passante de mémoire ou du taux de remplissage.

  • La bande passante de mémoire est le débit des lectures et des écritures que peut avoir le processeur graphique à partir de la mémoire
    • Dans Unity, changez Texture Quality dans Edit>Project Settings>Quality Settings.
  • Le taux de remplissage fait référence aux pixels qui peuvent être dessinés par seconde par le processeur graphique.

Optimiser le partage du tampon de profondeur

Nous vous recommandons d’activer Depth buffer Sharing pour optimiser la stabilité de l’hologramme. Quand vous activez la reprojection au stade tardif basée sur la profondeur avec ce paramètre, nous vous recommandons de sélectionner le format de profondeur 16 bits au lieu de 24 bits. Les tampons de profondeur 16 bits réduisent considérablement la bande passante (et donc la puissance) associée au trafic du tampon de profondeur. Cela peut apporter une grande amélioration à la fois en termes de réduction de puissance et d’amélioration des performances. Toutefois, il existe deux résultats négatifs possibles avec l’utilisation du format de profondeur 16 bits.

Z-Fighting

La fidélité à une plage de profondeur réduite rend le z-fighting plus susceptible de se produire avec 16 bits qu’avec 24 bits. Pour éviter ces artefacts, modifiez les plans de découpage proche/lointain de la caméra Unity pour tenir compte de cette moindre précision. Pour les applications HoloLens, un plan de découpage lointain de 50 m au lieu des 1 000 m par défaut d’Unity peut en général éliminer tout z-fighting.

Tampon de gabarit désactivé

Quand Unity crée une texture de rendu avec une profondeur de 16 bits, aucun tampon de gabarit n’est créé. La sélection du format de profondeur 24 bits, comme décrit dans la documentation Unity, va créer un tampon z-buffer de 24 bits et un tampon de gabarit de 8 bits (si 32 bits sont applicables sur un appareil (par exemple, le HoloLens), ce qui est généralement le cas).

Éviter les effets plein écran

Les techniques qui fonctionnent en mode plein écran peuvent être coûteuses, car leur ordre de grandeur s’élève à des millions d’opérations pour chaque image. Il est recommandé d’éviter les effets de post-traitement, comme l’anticrénelage, un écart des doigts paume vers le haut, etc.

Paramètres d’éclairage optimaux

L’illumination globale en temps réel dans Unity peut donner des résultats visuels époustouflants, mais implique des calculs d’éclairage coûteux. Nous recommandons de désactiver l’illumination globale en temps réel pour chaque fichier de scène Unity via Window>Rendering>Lighting Settings> décochez Real-time Global Illumination.

En outre, il est recommandé de désactiver la projection d’ombres, car elle ajoute également des passes de GPU coûteuses à une scène Unity. Les ombres peuvent être désactivées par lumière, mais également contrôlées de façon holistique par le biais des paramètres de qualité.

Edit>Project Settings, puis la catégorie Quality> sélectionnez Low Quality pour la plateforme UWP. Vous pouvez également affecter simplement à la propriété Shadows la valeur Disable Shadows.

Nous vous recommandons d’utiliser l’éclairage baked avec vos modèles dans Unity.

Réduire le nombre de polygones

Le nombre de polygones est réduit par les opérations suivantes :

  1. Suppression d’objets dans une scène
  2. Décimation des ressources qui réduit le nombre de polygones pour un maillage donné
  3. Implémentation d’un système de niveau de détail (LOD) dans votre application qui restitue des objets lointains avec une version polygonale moindre de la même géométrie

Présentation des nuanceurs dans Unity

Une approximation facile pour comparer les performances des nuanceurs consiste à identifier le nombre moyen d’opérations que chacun exécute au moment de l’exécution. Cette opération est simple dans Unity.

  1. Sélectionnez votre ressource de nuanceur ou un matériau puis, dans le coin supérieur droit de la fenêtre de l’inspecteur, sélectionnez l’icône en forme d’engrenage, puis « Select Shader »

    Select Shader dans Unity

  2. Une fois la ressource de nuanceur sélectionnée, sélectionnez le bouton « Compile and show code » sous la fenêtre de l’inspecteur

    Compile Shader Code dans Unity

  3. Après la compilation, recherchez dans la section des statistiques des résultats le nombre d’opérations différentes pour le nuanceur de vertex et de pixels (remarque : les nuanceurs de pixels sont souvent également appelés nuanceurs de fragments).

    Opérations des nuanceurs standard Unity

Optimiser les nuanceurs de pixels

En examinant les résultats des statistiques compilés à l’aide de la méthode ci-dessus, le nuanceur de fragments exécute généralement plus d’opérations que le nuanceur de vertex, en moyenne. Le nuanceur de fragments, également connu sous le nom de nuanceur de pixels, est exécuté par pixel sur la sortie d’écran, tandis que le nuanceur de vertex est exécuté uniquement par vertex de tous les maillages dessinés à l’écran.

Ainsi, non seulement les nuanceurs de fragments ont plus d’instructions que les nuanceurs de vertex en raison de tous les calculs d’éclairage, mais les nuanceurs de fragments sont aussi presque toujours exécutés sur un jeu de données plus volumineux. Par exemple, si la sortie d’écran est une image 2k par 2k, alors le nuanceur de fragments peut être exécuté 2 000 * 2 000 = 4 millions de fois. En cas de rendu de deux yeux, ce nombre double puisqu’il y a deux écrans. Si une application de réalité mixte a plusieurs passes, des effets de post-traitement plein écran ou un rendu de plusieurs maillages sur le même pixel, ce nombre augmente considérablement.

Par conséquent, la réduction du nombre d’opérations dans le nuanceur de fragments peut entraîner des gains de performance bien supérieurs aux optimisations dans le nuanceur de vertex.

Alternatives aux nuanceurs standard Unity

Au lieu d’utiliser un rendu physique ou un autre nuanceur haute qualité, envisagez d’utiliser un nuanceur plus performant et moins onéreux. Mixed Reality Toolkit fournit le nuanceur standard MRTK optimisé pour les projets de réalité mixte.

Unity fournit également des options de nuanceur simplifiées, comme l’absence d’éclairage, l’éclairage des vertex et la lumière diffuse, qui sont plus rapides par rapport au nuanceur Unity standard. Pour plus d’informations, consultez Utilisation et performances des nuanceurs intégrés.

Préchargement des nuanceurs

Utilisez le préchargement des nuanceurs et d’autres astuces pour optimiser le temps de chargement des nuanceurs. Plus particulièrement, le préchargement des nuanceurs signifie que vous ne rencontrerez aucune anicroche en raison de la compilation des nuanceurs au moment de l’exécution.

Limiter le surdessin

Dans Unity, vous pouvez afficher le surdessin pour votre scène, en utilisant le menu du mode dessin dans le coin supérieur gauche de la vue de la scène et en sélectionnant Overdraw.

En règle générale, le surdessin peut être atténué en éliminant les objets à l’avance avant leur envoi au GPU. Unity fournit des détails sur l’implémentation de l’élimination des occlusions pour son moteur.

Recommandations sur la mémoire

Les opérations d’allocation et de désallocation de mémoire excessives peuvent avoir des effets négatifs sur votre application holographique, entraînant des performances irrégulières, des frames figées et d’autres comportements néfastes. Il est particulièrement important de bien comprendre les considérations relatives à la mémoire pour développer dans Unity, car la gestion de la mémoire est contrôlée par le garbage collector.

Nettoyage de la mémoire

Les applications holographiques perdent du temps de calcul de traitement dans le garbage collector (GC) quand le GC est activé pour analyser des objets qui ne sont plus dans la portée pendant l’exécution et quand leur mémoire doit être libérée, de sorte à être rendue disponible à des fins de réutilisation. Les allocations et désallocations constantes nécessitent généralement que le garbage collector s’exécute plus fréquemment, ce qui nuit aux performances et à l’expérience utilisateur.

Unity propose une excellente page qui explique précisément comment le garbage collector fonctionne et donne des conseils pour écrire du code plus efficace en termes de gestion de la mémoire.

L’une des pratiques les plus courantes qui conduisent à un nettoyage de la mémoire excessif consiste à ne pas mettre en cache les références aux composants et aux classes dans le développement Unity. Toutes les références doivent être capturées pendant Start() ou Awake() et réutilisées dans des fonctions ultérieures comme Update() ou LateUpdate().

Autres conseils rapides :

  • Utilisez la classe C# StringBuilder pour créer dynamiquement des chaînes complexes au moment de l’exécution.
  • Supprimez les appels à Debug.log() quand vous n’en avez plus besoin, car ils s’exécutent encore dans toutes les versions de build d’une application.
  • Si votre application holographique nécessite généralement beaucoup de mémoire, envisagez d’appeler System.GC.Collect() pendant les phases de chargement, par exemple lors de la présentation d’un écran de chargement ou de transition.

Mise en pool d’objets

Le mise en pool d’objets est une technique connue pour réduire le coût des allocations et désallocations continues d’objets. Pour la réaliser, vous devez allouer un grand pool d’objets identiques et réutiliser des instances inactives disponibles de ce pool au lieu de générer et détruire constamment des objets au fil du temps. Les pools d’objets conviennent parfaitement aux composants réutilisables qui ont une durée de vie variable pendant une application.

Performances de démarrage

Envisagez de démarrer votre application avec une scène plus petite, puis d’utiliser SceneManager.LoadSceneAsync pour charger le reste de la scène. Cela permet à votre application d’accéder à un état interactif aussi rapidement que possible. Il peut y avoir un pic de consommation de processeur important pendant l’activation de la nouvelle scène et que tout contenu rendu peut être saccadé ou figé. Pour contourner ce problème, vous pouvez affecter à la propriété AsyncOperation.allowSceneActivation la valeur « false » sur la scène en cours de chargement, attendre que la scène se charge, effacer l’écran de sorte à ce qu’il soit noir, puis affecter la valeur « true » pour terminer l’activation de la scène.

N’oubliez pas que pendant le chargement de la scène de démarrage, l’écran de démarrage holographique est présenté à l’utilisateur.

Voir aussi