Unity Addressables: toujours assez de mémoire

image

Vous dirigez une équipe de plusieurs programmeurs et artistes travaillant sur le portage d'un magnifique jeu PS4 VR sur Oculus Quest. Vous avez six mois pour le faire. Quel sera votre premier coup? Essayons d'utiliser Unity Addressables.

Vous comprenez que vous devez résoudre plusieurs tâches assez difficiles en même temps. Certains seront plus difficiles pour vous que d'autres, cela dépend de votre expérience dans chacun des domaines. Si vous choisissez lequel d'entre eux vous a le plus privé de sommeil, alors quel sera-t-il?

Je suppose ce qui suit: environ 70% des lecteurs diront que le plus gros problème lors du portage d'un jeu vers Quest est la performance CPU / GPU. Je peux répondre à ceci: vous avez très probablement raison. L'amélioration de la productivité est l'un des domaines les plus difficiles d'un jeu VR. Les optimisations de ce type nécessitent une étude approfondie du produit, ce qui prend du temps. Parfois, une optimisation supplémentaire est impossible, à cause de laquelle vous devez généralement vous débarrasser des éléments coûteux du gameplay et des graphismes. Et il est dangereux de décevoir les joueurs.

Vitesse, vitesse, vitesse ... Qu'attendre à cet égard de la plateforme Quest? Quelle est sa productivité? Le fait est que si vous avez déjà de l'expérience dans son développement, vous savez que malgré sa mobilité, il est étonnamment puissant.

«Allez, auteur, pourquoi tu mens? Mon téléphone commence à ralentir dès que j'ouvre le deuxième onglet du navigateur. Comment pouvez-vous dire que les plateformes mobiles peuvent être productives? »

La grande différence réside dans le système de refroidissement actif Quest , qui donne un énorme avantage à son CPU / GPU qui n'est fourni par aucune autre plate-forme mobile. Il s'agit d'un ventilateur puissant qui souffle la poussière de vos cheveux et empêche le processeur de fondre sur votre visage.

De plus, un OS plus spécialisé est mieux optimisé pour le rendu de réalité virtuelle (surprise) qu'un Android standard. Au cours des dernières années, le matériel mobile a commencé à rattraper rapidement les plates-formes fixes.

Mais en même temps, je ne nierai pas que la tâche de rendu constant avec une fréquence de 72 fps sera difficile, surtout pour les ports de jeux VR qui proviennent de plateformes puissantes. Lorsque nous parlons d'Oculus Quest, vous pouvez imaginer le Snapdragon 835 avec un écran, une batterie, quatre caméras et un ventilateur.

Ce qui ressemble à un défaut peut en fait être considéré comme un avantage. Cette plate-forme mobile est un appareil bien étudié avec du fer faible. Nous pouvons dire qu'il existe mille astuces connues pour réduire rapidement la charge du CPU et du GPU à un niveau acceptable. Si vous êtes intéressé, vous pouvez en lire plus dans mes articles suivants. Et dans cet article, nous mettrons la performance hors de question.

Notre attention sur ce problème peut être que, par rapport à la PS4, Quest a une caractéristique matérielle deux fois moins importante: la capacité de RAM . À savoir, le volume est passé de 8 à 4 Go de RAM. Il s'agit d'une approximation, car sur les deux plates-formes, le système d'exploitation ne permet pas de les utiliser complètement, afin que vous puissiez suivreplusieurs sous-systèmes nécessaires au fonctionnement de l'écosystème. Dans Quest, vous pouvez utiliser jusqu'à environ 2,2 Go de RAM; si plus, le chaos commence déjà.

"Mais qu'entendez-vous par chaos ?" Le fait est que pour le jeu, il est essentiel de mettre en œuvre la bonne gestion de la mémoire. C'est arrivé parce que nous avons deux limites:

  • Limite de mémoire dure : si vous dépassez un certain seuil, le système d'exploitation tuera simplement le jeu
  • Limite de mémoire douce

Évidemment, nous ne voulons pas que le premier ou le deuxième se produise dans le jeu. Pouvez-vous imaginer la fureur d'un joueur qui a perdu les deux dernières heures de passe? Oui, il ira certainement au magasin d'applications et n'y dira rien de plaisant.

Bien sûr, la disponibilité garantie de 2,2 Go de RAM n'est pas tellement. Habituellement, ce n'est pas un problème pour les nouveaux projets dans lesquels les statistiques sont constamment surveillées dès le début, mais cela devient définitivement une difficulté pour un port avec un matériel beaucoup plus faible.

Si vous avez déjà utilisé des ports similaires par le passé, vous vous rendrez rapidement compte qu'il est extrêmement difficile de réduire de moitié la quantité de RAM disponible . Cela dépend beaucoup de la façon dont l'architecture du jeu était prête pour un tel changement, mais dans la plupart des cas, cela ne fait que pleurer.

Les stratégies les plus courantes pour réduire les besoins en mémoire sont la modification des paramètres de compression des actifs, l'optimisation des scripts, la réduction des variations de shader, etc. Le plus souvent, la toute première solution consiste à modifier les options d'importation des textures, mais si nécessaire, vous pouvez utiliser la compression des maillages, des animations et du son. Le problème est que ces techniques sont généralement complexes et ont leur propre plafond .

Toutes les plates-formes ne prennent pas en charge les mêmes paramètres d'importation: lors du développement pour différents appareils, les coûts du pipeline d'assemblage augmentent considérablement, sans parler de la complexité de l'assurance qualité, de la conception graphique et de la programmation. Par exemple, cela prend-il en charge le périphérique Android ASTC, ou seulement ETC2 (et généralement l'un d'entre eux)? Oh, et nous avons toujours besoin de versions 64 bits, mais en même temps, nous voulons garder les joueurs avec des versions 32 bits. De combien de fichiers APK individuels avons-nous besoin pour créer et tester chaque mise à jour du jeu? Si vous voulez vous simplifier la vie, vous ne devez pas vous fier uniquement à ces techniques.

Par conséquent, nous devons aller plus loin. Bien sûr, nous voulons que tout soit aussi simple que possible, en particulier lors de la création d'un port. Recycler le jeu entièrement pour les performances est une option encore pire que de ne pas le porter. Dans le cadre du sujet de l'article, je montrerai l'un des avantages les plus importants: vous apprendrez à réduire de moitié la quantité de mémoire requise en quelques heures seulement .

n'est-ce pas génial?

Eh bien, demandons-moi: est-ce vraiment possible dans votre cas? Je vais répondre: cela dépend des conditions initiales, mais d'après mon expérience, la réponse est OUI . Unity Addressables peut rendre un excellent service ici. Quelle est l'astuce? Vous devez investir et maîtriser le processus. Mais un tel workflow vous permettra de remporter le titre d'employé du mois.

Si vous êtes intéressé, poursuivez votre lecture.

Dans ce billet, nous passerons de la gestion d' actifs traditionnelle à la gestion d' actifs adressable . Pour illustrer ce processus, nous portons un projet simplifié à l'ancienne vers la nouvelle ère des adressables Unity.

Vous pouvez poser une question: pourquoi ne montrez-vous pas simplement le résultat à votre vrai travail?

Dans un monde sans compétition, je voudrais juste vous montrer tous les matériaux que j'ai créés. Cependant, dans le monde réel, je serai très probablement puni pour cela. Et puis ils me mettront en prison.

Alors au lieu de cela, je propose mon aide: nous élaborons un projet qui présente toutes les difficultés que vous rencontrerez demain dans votre prochain projet. Et pour commencer, nous intégrerons Unity Addressables dans notre famille de packages recommandés .

Dans cet article, je vais vous présenter Addressables afin que vous puissiez implémenter votre propre système Unity Addressables en quelques minutes .


Unity Addressables: pourquoi sont-ils nécessaires?


Il convient de prêter attention à cette section importante. Notre tâche consiste à identifier des moyens simples d'optimiser l'utilisation de la mémoire et de les implémenter rapidement. Il existe différentes façons de le faire, mais l'une des plus puissantes et en même temps la plus simple consiste à charger la première scène et à lancer le profileur. Pourquoi?

Parce que l' architecture non optimisée du jeu peut être reconnue à tout moment du gameplay , le moyen le plus rapide de vérifier cela est de profiler la première scène. La raison en est que l'utilisation souvent trop active de scripts comme singleton-s contenant des liens vers tous les actifs, juste au cas où .

En d'autres termes, de nombreux jeux ont généralement un script omnipotent qui crée un enfer de liens vers des actifs .Ce composant garde chaque actif chargé en permanence, qu'il soit actuellement utilisé ou non.

C'est pas terrible?

Les situations sont différentes. Si votre jeu est susceptible d'être limité par la mémoire? alors c'est une décision très risquée, car le jeu n'évolue pas bien avec l'augmentation du nombre d'actifs ajoutés (par exemple, pensez aux futurs DLC). Si vous développez pour des appareils hétérogènes, par exemple pour Android, vous n'avez pas une seule quantité de mémoire; Chaque appareil a sa propre capacité, vous devez donc compter sur le pire des cas. Le système d'exploitation peut décider de tuer l'application à tout moment si l'utilisateur passe soudainement pour répondre à un message sur Facebook. A son retour, une surprise l'attendra - le jeu est déjà clos.

Est-ce amusant?

Absolument pas.

Pour compliquer la situation, si vous décidez plus tard (ou si quelqu'un décide pour vous) de porter le jeu sur une autre plate-forme moins puissante tout en conservant le jeu croisé, vous ne pouvez que souhaiter bonne chance. Vous ne voudrez certainement pas faire face à un tel problème technique.

D'un autre côté, existe-t-il des situations dans lesquelles la gestion d'actifs traditionnelle est appropriée? Oui bien sûr. Si vous développez pour une plate-forme uniforme, comme pour PS4, et que la plupart des exigences sont connues dès le début, les avantages des objets globaux pourraient potentiellement l'emporter sur la complexité supplémentaire d'un système de gestion de mémoire amélioré.

Parce que vous devez l'admettre: le bon vieil objet global qui stocke tout ce dont nous avons besoin est une solution simple si cela vous convient. Il simplifiera le code et préchargera tous les actifs référencés.

Quoi qu'il en soit, la gestion de la mémoire traditionnelle est inacceptable pour les développeurs qui cherchent à maximiser l'utilisation des ressources en fer . Vous lisez un article, ce qui signifie que vous souhaitez améliorer vos compétences. Le moment est donc venu de le faire.

Rencontrez Unity Addressables.

Exigences du projet avec Unity Addressables


Si vous prévoyez de lire ce post, l'écran sera suffisant. Si tu veux tout faire avec moi. alors vous aurez besoin des éléments suivants:

  • Mains
  • Esprit intelligent
  • Unity 2019.2.0f1 ou supérieur
  • Projet de niveau 1 avec GitHub (téléchargement zip ou via ligne de commande)
  • Le désir de se plonger dans l'intérieur de Unity Addressables

Le référentiel git contient trois commits, un pour chaque niveau de ce post (sauf si je mélange quelque chose et crée un commit avec un correctif).

Téléchargez le projet au format ZIP directement depuis GitHub


Développeur de niveau 1: Gestion traditionnelle des actifs


Nous commencerons par la méthode de gestion d'actifs la plus simple. Dans notre cas, pour cela, nous devons faire une liste de liens directs vers les matériaux skybox dans le composant.

Si vous faites cela avec moi, la préparation prendra trois étapes simples:

  1. Téléchargez le projet depuis git
  2. Ouvrir un projet dans Unity
  3. Cliquez sur le bouton de lecture!

Bien. Vous pouvez maintenant cliquer sur les boutons pour changer la skybox. Tellement original ... et ennuyeux. Si je comprends bien, jusqu'à présent aucun Unity Addressables.

Bientôt, vous verrez pourquoi nous endurons ces moments d'ennui.

Premièrement, comment est structuré notre projet? Il repose sur deux systèmes principaux. D'une part, nous avons un objet Game manager . Ce composant est le script principal qui stocke les liens vers les matériaux skybox et les change en fonction des événements de l'interface utilisateur. C'est assez simple.

using UnityEngine;

public class Manager : MonoBehaviour
{
    [SerializeField] private Material[] _skyboxMaterials;

    public void SetSkybox(int skyboxIndex)
    {
        RenderSettings.skybox = _skyboxMaterials[skyboxIndex];
    }
}

Manager fournit au système d'interface utilisateur une fonction pour appliquer un matériau spécifique à la scène via l'utilisation de l'API RenderSettings .

Deuxièmement, nous avons un CanvasSkyboxSelector . Cet objet de jeu contient un composant de canevas qui rend un ensemble de boutons répartis verticalement. Chaque bouton, lorsqu'il est enfoncé, appelle la fonction de gestionnaire susmentionnée , qui remplace la skybox rendue en fonction de l'ID du bouton. En d'autres termes, l'événement OnClick de chaque bouton appelle la fonction SetSkybox de l' objet Manager . C'est simple, non?


Unity Addressables - hiérarchie des scènes

Il est maintenant temps de commencer. Ouvrons le profileur ( ctrl / cmd + 7 ou Fenêtre - Analyse - Profileur ). Je suppose que vous connaissez cet outil, ce qui signifie que vous savez quoi faire avec le bouton d' enregistrement supérieur . Après quelques secondes d'enregistrement, arrêtez-le et regardez les métriques: CPU, mémoire, etc. Y a-t-il quelque chose d'intéressant?

Les performances sont plutôt bonnes, ce qui n'est pas surprenant étant donné l'ampleur du projet. Vous pouvez simplement transformer ce projet en jeu VR et je garantis qu'aucun des joueurs ne se sentira malade, comme c'est souvent le cas dans Eve: Valkyrie .

Dans notre cas, nous nous concentrerons sur la section mémoire. En mode d'affichage simple, vous verrez quelque chose comme ceci:


Level 1 Asset Management - Simple Memory Profiling Les

valeurs de taille de texture semblent trop grandes pour afficher une skybox à la fois, n'est-ce pas? Une surprise vous attend: un schéma similaire se retrouve dans de nombreux jeux non optimisés, dont vous dirigerez le développement . Mais dans notre cas, ce n'est qu'un ensemble de skyboxes. Dans d'autres projets, ce seront des personnages, des planètes, des sons, de la musique ...

Si la responsabilité de travailler avec de nombreux atouts vous incombe, alors je suis heureux que vous lisiez cet article. Je vais vous aider à faire la transition vers une solution qui évolue bien.

Le temps est venu pour la magie. Basculez le profileur de mémoire en mode détaillé. Regarde ça!


Gestion des actifs de niveau 1 - Profilage détaillé de la mémoire

Bon sang, que s'est-il passé ici? Toutes les textures skybox sont chargées en mémoire, mais une seule d'entre elles est affichée à la fois. Vous voyez ce que nous avons? Cette architecture brute prend jusqu'à 400 MB .

Cela ne nous convient absolument pas, étant donné qu'il ne s'agit que d'un petit morceau du futur jeu. La solution à ce problème lui-même deviendra la base de la section suivante.

Résumer:

  • La gestion d'actifs traditionnelle implique des liens directs
  • Par conséquent, tous les objets sont constamment chargés
  • Le projet ne se déroule pas bien


Développeur de niveau 2: Processus adressables Unity


Dans les jeux, nous partons du niveau 1, et cela nous convient, mais dès que nous comprenons les règles du gameplay, il est temps de quitter les murs de la ville et d'augmenter notre niveau. C'est à cela que sert cette section.

Téléchargez maintenant le projet de niveau 2 .

Comme nous l'avons vu précédemment dans le profileur, toutes les skybox sont chargées en mémoire, même si une seule est activement utilisée . Cette solution n'est pas évolutive, car à un certain stade, nous serons limités par le nombre de variations d'actifs différentes que nous pouvons offrir au joueur. Quels conseils puis-je donner? Ne limitez pas l'intérêt du jeu aux utilisateurs.

Laissez-moi vous aider. Prenez une pelle pour creuser un tunnel de jailbreak de la gestion traditionnelle des actifs. Ajoutons un nouvel outil intéressant à notre collection: l'API Unity Addressables .

La première chose que nous devons faire est d'installer le package Addressables. Pour ce faire, allez dans Fenêtre → Gestionnaire de packages :


Unity Package Manager - Unity Addressables

Après l'installation, nous devons marquer les matériaux comme étant adressables. Sélectionnez-les et activez l'indicateur adressables dans la fenêtre d'inspection.


Gestion des actifs de niveau 2 (Unity Addressables)

Nous demandons donc poliment à Unity d'inclure ces matériaux et leurs dépendances de texture dans la base de données des adressables. Cette base de données sera utilisée lors des builds pour regrouper les actifs en morceaux, qui peuvent être facilement chargés à tout moment dans le jeu.

Maintenant, je vais vous montrer quelque chose de cool. Ouvrez la fenêtre -> Asset Management -> Addressables . Devinez ce que c'est? C'est notre base de données qui a hâte de prendre vie!


La gestion de l'actif de niveau 2 Unity Addressables est la fenêtre principale

Cher lecteur, c'était la partie facile. Et maintenant, le plaisir commence.

Je veux que vous rendiez visite à notre vieil ami de la section précédente: Sir Manager . Si nous le vérifions, nous constaterons qu'il stocke toujours des liens directs vers les actifs! Nous n'en avons pas besoin.

Au lieu de cela, nous enseignerons au gestionnaire comment utiliser les liens indirects, c'est-à-dire AssetReference (dans Unreal Engine, ils sont appelés références logicielles ).

Rendons notre composant plus beau:

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class Manager : MonoBehaviour
{
    [SerializeField] private List<AssetReference> _skyboxMaterials;

    private AsyncOperationHandle  _currentSkyboxMaterialOperationHandle;

    public void SetSkybox(int skyboxIndex)
    {
        StartCoroutine(SetSkyboxInternal(skyboxIndex));
    }

    private IEnumerator SetSkyboxInternal(int skyboxIndex)
    {
        if (_currentSkyboxMaterialOperationHandle.IsValid())
        {
            Addressables.Release(_currentSkyboxMaterialOperationHandle);
        }

        var skyboxMaterialReference = _skyboxMaterials[skyboxIndex];
        _currentSkyboxMaterialOperationHandle = skyboxMaterialReference.LoadAssetAsync();
        yield return _currentSkyboxMaterialOperationHandle;
        RenderSettings.skybox = _currentSkyboxMaterialOperationHandle.Result;
    }
}

Voici ce qui se passe:

  • 7, (AssetReference) . , . . .
  • 13: , . ,
  • 18-20 , , , , . , API Addressables, , . — , , addressable-.
  • addressable 23, LoadAssetAsync, yield ( 25), . . !
  • , , , 26. Result, , .


Niveau 2 Asset Management (Unity Addressables) - Liste AssetReference

Rappel: ce code n'est pas prêt pour la production. Ne l'utilisez pas lors de la programmation d'un avion. J'ai décidé que pour des raisons de simplicité, sacrifier la fiabilité.

Mais assez d'explications. Il est temps de le voir en action.

Veuillez suivre ces étapes:

  1. Dans la fenêtre des adressables, préparez le contenu ( créer le contenu du lecteur )
  2. Puis construisez pour la plateforme sélectionnée
  3. Exécutez-le et connectez-y le profileur (mémoire).
  4. Ne laissez pas tomber votre mâchoire de surprise.


Niveau 2 (Unity Addressables) - Construire le contenu du joueur


Gestion de la mémoire de niveau 2 (Unity Addressables) - Memory Profiler

Les actifs cuits ne sont-ils pas savoureux?

J'aime quand le profileur est satisfait. Et maintenant, nous voyons le profileur le plus heureux du monde. Un profileur satisfait signifie ce qui suit: premièrement, il y a des joueurs plus satisfaits qui peuvent jouer à votre jeu même sur Nokia 3210 . Deuxièmement, ce sont des producteurs satisfaits. Et pour vous, cela signifie que votre portefeuille sera satisfait.

C'est la puissance du système Addressables.

Mais les adressables imposent de petits coûts de main-d'œuvre supplémentaires. D'une part, les programmeurs doivent fournir un support pour les workflows asynchrones (cela est facilement implémenté à l'aide de coroutine). De plus, les concepteurs devront étudier les capacités du système, par exemple les groupes adressables, et acquérir de l'expérience pour prendre des décisions éclairées. Enfin, le service informatique sera très heureux que vous deviez configurer l'infrastructure de transfert des actifs sur le réseau si vous préférez les héberger en ligne.

Je dois te féliciter. Je vais expliquer ce que nous avons accompli:

  • Bonne gestion de la mémoire.
  • Démarrage plus rapide.
  • Temps d'installation plus rapide, taille d'application réduite dans le magasin.
  • Augmentation de la compatibilité des appareils.
  • Architecture asynchrone.
  • Ils ont ouvert la porte au stockage de ce contenu en ligne → c'est-à-dire à la séparation des données du code.

Je serais fier de ces réalisations. Il s'agit d'un bon retour sur notre investissement en main-d'œuvre.

Oh, et n'oubliez pas de mentionner l'expérience avec Addressables dans une interview.

Supports: création d'instances et comptage de liens. Des informations sur ce sujet peuvent être trouvées dans mon article .

Facultatif: stratégies de téléchargement alternatives. Vous pouvez les lire dans mon article .

Résumer:

  • La gestion des actifs basée sur les adressables évolue remarquablement bien.
  • Les adressables ajoutent un comportement asynchrone
  • N'oubliez pas de préparer le contenu pour les changements, sinon le jeu aura une teinte rosée!


Gestion des actifs de niveau 3 (??) - Livraison de contenu réseau

Gestion des actifs de niveau 3 (??) - Livraison de contenu réseau


Dans la section précédente, nous avons réalisé la percée la plus importante. Améliorez vos compétences en passant d'un système de gestion d'actifs traditionnel à un workflow basé sur des adressables. Il s'agit d'une énorme victoire pour le projet, car grâce au petit investissement en temps, nous avons fourni un espace pour faire évoluer le volume des actifs, tout en maintenant un faible niveau de consommation de mémoire. Cette réalisation vous a en fait amélioré au niveau 2, félicitations! Cependant, nous devons encore répondre à une autre question:

est-ce tout?

Non . Nous avons à peine abordé le sujet des adressables, il existe d'autres façons d'améliorer le projet grâce à ce puissant package.

Bien sûr, vous n'avez pas besoin de vous souvenir de tous les détails de l'utilisation d'Adressables, mais je vous recommande fortement de les lire brièvement, car à l'avenir, vous rencontrerez très probablement de nouveaux tests et vous serez reconnaissant pour une étude plus approfondie. C'est pourquoi j'ai préparé un autre petit guide.

Vous en apprendrez plus sur les aspects suivants:

  • Fenêtre des adressables : détails importants
  • Profilage adressable : ne laissez pas les fuites de mémoire vous gâcher la vie
  • Livraison réseau : temps réduit de l'installation au gameplay
  • Intégration du pipeline d' assemblage
  • Stratégies pratiques : accélérer le flux de travail, éliminer le besoin de pauses café de dix minutes

Et, plus important encore, nous répondrons aux questions suivantes:

  • Quelle est la signification cachée de Send Profiler Events ?
  • Quelle est l'utilité de l'API AddressableAssetSettings ?
  • Comment intégrer tout cela avec l'API BuildPlayerWindow ?
  • Quelle est la différence entre le mode virtuel et le mode packé ?

Des conseils de niveau 3 peuvent être trouvés dans mon article .

All Articles