optimisation des performances graphiques

Une bonne performance est essentielle au succès de nombreux jeux. Voici quelques lignes directrices simples pour maximiser la vitesse de rendu de votre jeu.

Localiser l'impact graphique élevé

Les parties graphiques de votre jeu peuvent avoir un impact majeur sur deux systèmes de l'ordinateur: le GPU et le CPU. La première règle de toute optimisation est de trouver où est le problème de performance , parce que les stratégies d'optimisation pour GPU vs. CPU sont assez différentes (et peut même être contraire - par exemple, il est assez courant de faire fonctionner le GPU tout en optimisant la CPU, et vice versa).

    Les problèmes courants et les moyens de les vérifier :
  • Le GPU est souvent limité par le taux de remplissage ou la bande passante mémoire.
    Abaissez la résolution d'affichage et exécutez le jeu. Si une résolution d'affichage inférieure rend le jeu plus rapide, vous pouvez être limité par le taux de remplissage (fillrate) sur le GPU.
  • La CPU est souvent limitée par le nombre de paquets qui doivent être rendus.
    Vérifiez les "paquets" dans la fenêtre Statistiques de rendu (Rendering Statistics). Plus il y a de paquets en cours, plus le coût pour la CPU est élevé.

    Problèmes moins courants :
  • Le GPU a trop de vertices à traiter. Le nombre de vertices acceptables pour assurer une bonne performance dépend du GPU et de la complexité des shaders vertex. D'une manière générale, ne viser pas plus de 100 000 vertices sur mobile. Un PC gère bien même avec plusieurs millions de vertices, mais il est toujours recommandé de garder ce nombre le plus bas possible grâce à l'optimisation.
  • Le CPU a trop de vertices à traiter. Cela pourrait être dans des skinned meshes, une simulation de tissu, des particules, des maillages (meshes) ou d'autres objets du jeu. Comme ci-dessus, il est généralement recommandé de garder ce nombre aussi bas que possible sans compromettre la qualité du jeu. Consultez la section sur l'optimisation du CPU ci-dessous pour obtenir des conseils sur la façon de procéder.
  • Si le rendu n'est pas un problème sur le GPU ou le CPU, il peut y avoir un problème ailleurs - par exemple, dans votre script ou votre physique. Utilisez le Unity Profiler pour localiser le problème.

Optimisation du CPU

Pour afficher des objets à l'écran, le CPU a beaucoup de travail de traitement à faire : déterminer les lumières affectant cet objet, configurer le shader et les paramètres du shader, et envoyer des commandes de dessin au pilote graphique, qui prépare alors les commandes à envoyer à la carte graphique.

Toute cette utilisation de CPU "par objet" est gourmand en ressources, donc si vous avez beaucoup d'objets visibles, cela peut s'accumuler. Par exemple, si vous avez un millier de triangles, il est beaucoup plus facile pour le CPU si elles sont toutes dans un maillage, plutôt qu'un maillage (mesh) par triangle. Le coût des deux scénarios sur le GPU est très similaire, mais le travail effectué par le CPU pour rendre un millier d'objets (au lieu d'un) est sensiblement plus élevé.

    Réduisez le nombre d'objets visibles. Pour réduire la quantité de travail que le CPU doit faire :
  • Combinez les objets proches ensemble, soit manuellement, soit en utilisant le dosage par appel de tirage (draw call batching) d'Unity.
  • Utilisez moins de matériaux dans vos objets en mettant des textures distinctes dans un atlas de texture plus large.
  • Utiliser moins de choses qui font que les objets soient rendus plusieurs fois (tels que les reflets, les ombres et les lumières par pixel).

Combinez les objets de manière à ce que chaque maille ait au moins plusieurs centaines de triangles et n'utilise qu'un seul matériau pour l'ensemble du maillage. Notez que la combinaison de deux objets qui ne partagent pas de matériel ne vous donne aucune augmentation de performance. La raison la plus fréquente pour exiger de multiples matériaux est que deux mailles ne partagent pas les mêmes textures; Pour optimiser les performances du CPU, assurez-vous que tous les objets que vous combinez partagent les mêmes textures.

Lors de l'utilisation de nombreuses lumières de pixel dans le chemin de rendu (Forward rendering path), il y a des situations où la combinaison d'objets peut ne pas avoir de sens. Consultez la section Performances de l'éclairage ci-dessous pour savoir comment gérer cela.

GPU: optimisation de la géométrie du modèle

    Il existe deux règles de base pour optimiser la géométrie d'un modèle :
  • N'utilisez pas plus de triangles que nécessaire.
  • Essayez de garder le plus petit nombre possible de coutures de cartographie UV (UV mapping) et de sommets durs (edges) (sommets doublés).

Notez que le nombre réel de sommets que le matériel graphique doit traiter n'est généralement pas identique au numéro signalé par une application 3D. Les applications de modélisation affichent généralement le nombre de points d'angle distincts qui constituent un modèle (connu sous le nom de sommet géométrique). Pour une carte graphique, cependant, certains sommets géométriques doivent être répartis en deux ou plusieurs sommets logiques à des fins de rendu. Un vertex doit être fractionné s'il possède plusieurs normales, des coordonnées UV ou des couleurs de vertex. Par conséquent, le nombre de sommets dans Unity est généralement supérieur au nombre donné par l'application 3D.

Bien que la quantité de géométrie dans les modèles est principalement pertinent pour le GPU, certaines fonctionnalités dans Unity passe par le processus sur le CPU (par exemple, l'affinage des mailles).

Performance d'éclairage

L'option la plus rapide est toujours de créer un éclairage qui ne doit pas être du tout calculé. Pour ce faire, utilisez Lightmapping pour "bake" l'éclairage statique une seule fois, au lieu de la calculer chaque frame. Le processus de génération d'un environnement éclairé prend seulement un peu plus de temps que de placer une lumière dans la scène dans Unity, mais :

  • Il fonctionne beaucoup plus vite (2-3 fois plus rapide pour les lumières de 2 pixels par pixel)
  • Cela a l'air beaucoup mieux, car vous pouvez bake l'illumination globale et le lightmapper peut lisser les résultats.

Dans de nombreux cas, vous pouvez appliquer des astuces simples au lieu d'ajouter plusieurs lumières supplémentaires. Par exemple, au lieu d'ajouter une lumière qui brille directement dans la caméra pour donner un effet Rim Lighting, ajoutez un calcul de Rim Lighting dédié directement dans vos shaders.

La lumière dans le Forward rendering

L'éclairage dynamique par pixel ajoute un travail de rendu significatif à chaque pixel affecté et peut conduire à des objets en passe multiples. Évitez d'avoir plus d'une lumière pixel (Pixel Light) illuminant n'importe quel objet sur des périphériques moins puissants, comme les GPU pour mobiles ou les PC bas de gamme, et utiliser lightmaps pour allumer des objets statiques au lieu de calculer leur éclairage chaque frame. L'éclairage dynamique per-vertex peut ajouter un travail important aux transformations de vertex, alors essayez d'éviter les situations dans lesquelles plusieurs lumières éclairent un seul objet.

Évitez de combiner des maillages (meshes) suffisamment éloignés pour être affectés par différents ensembles de lumières de pixels. Lorsque vous utilisez l'éclairage par pixel, chaque maillage doit être rendu autant de fois qu'il y a des lumières de pixels qui l'illuminent. Si vous combinez deux meshes très éloignés, cela augmente la taille effective de l'objet combiné. Toutes les lumières de pixels qui illuminent toute partie de cet objet combiné sont prises en compte pendant le rendu, de sorte que le nombre de passes de rendu qui doivent être réalisées pourrait être augmenté. En général, le nombre de passes qui doivent être effectuées pour restituer l'objet combiné est la somme du nombre de passes pour chacun des objets distincts, donc rien n'est gagné en combinant des maillages.

Pendant le rendu, Unity trouve toutes les lumières qui entourent un maillage et calcule laquelle de ces lumières l'affecte le plus. Les paramètres de qualité sont utilisés pour modifier le nombre de lumières qui s'allument en tant que voyants en pixels et le nombre de lumières de vertex. Chaque lumière calcule son importance en fonction de la distance entre le maillage et l'intensité de son éclairage, et certaines lumières sont plus importantes que d'autres uniquement dans le contexte du jeu. Pour cette raison, chaque lumière a un paramètre de mode de rendu qui peut être réglé sur Important ou Not Important; les lumières marqués comme Not Important ont une surcharge de rendu inférieure.

Exemple: Imaginez un jeu de conduite dans lequel la voiture du joueur roule dans l'obscurité avec les phares allumés. Les phares sont probablement la source de lumière la plus visuellement significative dans le jeu, de sorte que leur mode de rendu doit être réglé sur Important. Il peut y avoir d'autres lumières dans le jeu qui sont moins importantes, comme les lumières arrière d'autres voitures ou les lampadaires éloignés, et qui n'améliorent pas beaucoup l'effet visuel en étant des lumières de pixel. Le mode de rendu pour de telles lumières peut sans risque être réglé sur Not Important pour éviter de gaspiller la capacité de rendu dans les endroits où elle a peu d'avantage.

L'optimisation de l'éclairage par pixel permet d'économiser à la fois le travail du CPU et du GPU : Le processeur (CPU) a moins d'appels à faire et le GPU a moins de sommets à traiter et de pixels à pixelliser pour tous les rendus d'objets supplémentaires.

GPU: compression de texture et mipmaps

Utilisez des textures compressées pour diminuer la taille de vos textures. Cela peut entraîner des temps de chargement plus rapides, une empreinte de mémoire plus petite et des performances de rendu considérablement accrues. Les textures compressées n'utilisent qu'une fraction de la bande passante requise pour les textures RGBA 32 bits non compressées.

Texture mipmaps

Activez toujours Generate mipmaps pour les textures utilisées dans une scène 3D. Une texture mipmap permet au GPU d'utiliser une texture de résolution inférieure pour les triangles plus petits. Cela est similaire à la façon dont la compression de texture peut aider à limiter la quantité de données de texture transférées lorsque le GPU est en cours de rendu.

La seule exception à cette règle est quand un Texel (pixel de texture) est connu pour mapper 1:1 au pixel d'écran rendu, comme avec des éléments d'interface utilisateur ou dans un jeu 2D.

LOD et distances de suppression par couche

Culling objects implique de rendre les objets invisibles. C'est un moyen efficace de réduire à la fois la charge CPU et GPU.

Dans de nombreux jeux, un moyen rapide et efficace de le faire sans compromettre l'expérience du joueur est d'éliminer les petits objets de manière plus agressive que les grands. Par exemple, de petites roches et des débris pourraient être rendus invisibles à de longues distances, alors que les grands bâtiments seraient encore visibles.

Il existe plusieurs façons d'y parvenir :

  • Utilisez le système Level Of Detail (LOD).
  • Définir manuellement des distances de suppression par couche sur la caméra.
  • Placez les petits objets dans une couche distincte et configurez les distances de suppression par couche à l'aide de la fonction de script Camera.layerCullDistances.

Ombres en temps réel

Les ombres en temps réel sont agréables, mais elles peuvent avoir un fort impact sur la performance, tant en termes d'appels de tirage supplémentaire pour le CPU que de traitement supplémentaire sur le GPU.

GPU: Conseils pour écrire des shaders haute performance

Différentes plates-formes possèdent des capacités de performance très différentes; Un GPU PC haut de gamme peut gérer beaucoup plus en termes de graphiques et d'ombres qu'un GPU mobile bas de gamme. La même chose est vraie même sur une plate-forme unique; un GPU rapide est des dizaines de fois plus rapide qu'un GPU intégré.

La performance d'un GPU sur les plates-formes mobiles et les PC basiques est susceptible d'être beaucoup plus faible que sur votre machine de développement. Il est recommandé d'optimiser manuellement vos shaders pour réduire les calculs et les lectures de texture, afin d'obtenir de bonnes performances dans les machines GPU bas de gamme. Par exemple, certains shaders intégrés dans Unity ont des équivalents «mobiles» qui sont beaucoup plus rapides, mais qui ont quelques limitations ou approximations.

Voici quelques lignes directrices pour les cartes graphiques mobiles et PC bas de gamme :

Opérations mathématiques complexes

Les fonctions mathématiques transcendantales (tel que pow, exp, log, cos, sin, tan) nécessitent beaucoup de ressources, alors évitez de les utiliser dans la mesure du possible. Envisagez d'utiliser des textures de recherche comme alternative aux calculs mathématiques complexes.

Évitez d'écrire vos propres opérations (tel que normalize, dot, inversesqrt). Les options intégrées d'Unity s'assurent que le pilote peut générer beaucoup mieux le code. N'oubliez pas que l'opération Alpha Test (discard) rend souvent votre shader de fragment plus lent.

Précision à virgule flottante

Bien que la précision des variables en virgule flottante (float vs half vs fixed) soit largement ignorée sur les GPU de bureau, il est très important d'obtenir une bonne performance sur les GPU mobiles.

Liste de contrôle simple pour rendre votre jeu plus rapide

  • Maintenez le nombre de vertex au-dessous de 200 k et 3M par frame lors du build pour le PC (selon le GPU cible).
  • Si vous utilisez des shaders intégrés, choisissez ceux des catégories Mobile ou Unlit. Ils travaillent également sur des plates-formes non mobiles, mais sont des versions simplifiées et rapprochées de shaders plus complexes.
  • Gardez le nombre de matériaux différents par scène faible, et partager autant de matériaux entre les différents objets que possible.
  • Définissez la propriété Static sur un objet non mobile pour permettre des optimisations internes comme le dosage statique (static batching).
  • N'utilisez qu'une seule lumière de pixel (de préférence directionnelle) affectant votre géométrie plutôt que des multiples.
  • Bake l'éclairage plutôt que d'utiliser un éclairage dynamique.
  • Utilisez les formats de texture compressés lorsque cela est possible et utilisez des textures 16 bits plutôt que des textures de 32 bits.
  • Évitez d'utiliser le brouillard si possible.
  • Utilisez Occlusion Culling pour réduire la quantité de géométrie visible et les draw-calls en cas de scènes statiques complexes avec beaucoup d'occlusion. Concevez vos niveaux avec la suppression d'occlusion.
  • Utilisez skyboxes pour "fausser" la géométrie distante.
  • Utilisez des pixel shaders ou des combinateurs de texture pour mélanger plusieurs textures au lieu d'une approche à plusieurs passages.
  • Utiliser des variables à demi précision si possible.
  • Réduire au minimum l'utilisation d'opérations mathématiques complexes telles que pow, sin et cos dans les shaders de pixels.
  • Utilisez moins de textures par fragment.

les réactions

Pour laisser un avis, vous devez être inscrit et connecté

Se connecter