Il s'agit du deuxième d'une série d'articles qui présente des conseils d'optimisation pour vos projets Unity. Utilisez-les comme guide pour fonctionner à des fréquences d'images plus élevées avec moins de ressources. Une fois que vous avez essayé ces bonnes pratiques, assurez-vous de consulter les autres pages de la série :
Les outils graphiques de Unity vous permettent de créer des graphiques optimisés dans n'importe quel style, sur une gamme de plates-formes – du mobile aux consoles et ordinateurs de bureau haut de gamme. Ce processus dépend généralement de votre direction artistique et de votre pipeline de rendu. Par conséquent, avant de commencer, nous vous recommandons de consulter les pipelines de rendu disponibles.
Lorsque vous choisissez un pipeline de rendu, tenez compte de ces considérations . En plus de choisir un pipeline, vous devrez sélectionner un chemin de rendu.
Le chemin de rendu représente une série spécifique d'opérations liées à l'éclairage et à l'ombrage. Le choix d'un chemin de rendu dépend des besoins et du matériel cible de votre application.
Chemin de rendu avant
Le rendu direct est utilisé à la fois dans le pipeline de rendu universel (URP) et dans le pipeline de rendu intégré. Dans le rendu Forward, la carte graphique projette la géométrie et la divise en sommets. Ces sommets sont ensuite décomposés en fragments, ou pixels, qui s'affichent à l'écran, créant ainsi l'image finale.
Le pipeline transmet chaque objet, un à la fois, à l'API graphique. Le rendu direct a un coût pour chaque lumière, donc plus il y a de lumières dans votre scène, plus le rendu prendra du temps.
Le moteur de rendu direct du pipeline intégré dessine chaque lumière dans un passage distinct par objet. Si plusieurs lumières frappent le même GameObject, cela peut créer un overdraw important où les zones qui se chevauchent doivent dessiner le même pixel plus d'une fois. Pour réduire le dépassement, minimisez le nombre de lumières en temps réel.
Plutôt que de restituer un seul passage par lumière, l'URP sélectionne les lumières par objet. Cela permet de calculer l'éclairage en un seul passage, ce qui entraîne moins d'appels de tirage par rapport au moteur de rendu direct du pipeline de rendu intégré.
Le pipeline de rendu intégré, l'URP et le pipeline de rendu haute définition (HDRP) utilisent également le chemin de rendu Deferred Shading. Dans Deferred Shading, l’éclairage n’est pas calculé par objet.
Au lieu de cela, Deferred Shading reporte le rendu important, tel que l'éclairage, à une étape ultérieure et utilise deux passes. Dans la première passe, également appelée passe géométrique du tampon G , Unity restitue les GameObjects. Cette passe récupère plusieurs types de propriétés géométriques et les stocke dans un ensemble de textures.
Les textures du tampon G peuvent inclure :
- Couleurs diffuses et spéculaires
- Lissé de la surface
-Occlusion
- Normales de l'espace mondial
- Émission + ambiance + réflexions + lightmaps
Lors de la deuxième passe, ou passe d'éclairage, Unity restitue l'éclairage de la scène en fonction du G-buffer. Imaginez parcourir chaque pixel et calculer les informations d'éclairage en fonction du tampon plutôt que des objets individuels. L’ajout de lumières sans projection d’ombres dans Deferred Shading n’entraîne pas la même baisse de performances qu’avec le rendu Forward.
Bien que le choix d'un chemin de rendu ne soit pas exactement une optimisation en soi, cela peut affecter la façon dont vous optimisez votre projet. Les autres techniques et flux de travail de cette section varient en fonction du pipeline de rendu et du chemin que vous sélectionnez.
HDRP et URP prennent en charge Shader Graph, une interface visuelle basée sur des nœuds pour la création de shaders. Il permet aux utilisateurs sans expérience en programmation de shaders de créer des effets d'ombrage complexes.
Plus de 150 nœuds sont actuellement disponibles dans Shader Graph. De plus, vous pouvez créer vos propres nœuds personnalisés avec l'API.
Chaque shader d'un Shader Graph commence par un Master Node, qui détermine la sortie du graphique. Construisez la logique du shader en ajoutant et en connectant des nœuds et des opérateurs dans l'interface visuelle.
Le Shader Graph passe ensuite dans le backend du pipeline de rendu. Le résultat final est un shader ShaderLab dont le fonctionnement est similaire à celui écrit en HLSL ou Cg.
L'optimisation d'un Shader Graph suit bon nombre des mêmes règles qui s'appliquent aux shaders HLSL ou Cg traditionnels ; un point important étant que plus votre Shader Graph effectue de traitement, plus cela aura un impact sur les performances de votre application.
Si vous êtes limité au processeur, l'optimisation de vos shaders n'améliorera pas la fréquence d'images, mais cela pourrait améliorer la durée de vie de votre batterie pour les plates-formes mobiles.
Si vous utilisez le GPU, suivez ces directives pour améliorer les performances avec Shader Graph :
Supprimez les nœuds inutilisés : Ne modifiez aucune valeur par défaut et ne connectez aucun nœud à moins que ces modifications ne soient nécessaires. Shader Graph compile automatiquement toutes les fonctionnalités inutilisées. Lorsque cela est possible, intégrez les valeurs dans les textures. Par exemple, au lieu d’utiliser un nœud pour éclaircir une texture, appliquez la luminosité supplémentaire à la ressource de texture elle-même.
Utilisez un format de données plus petit lorsque cela est possible : Pensez à utiliser Vector2 au lieu de Vector3, ou à réduire la précision (par exemple,la moitié au lieu de float), si votre projet le permet.
Réduire les opérations mathématiques : Les opérations de shader s'exécutent plusieurs fois par seconde, alors essayez d'optimiser les opérateurs mathématiques lorsque cela est possible. Essayez de mélanger les résultats au lieu de créer une branche logique. Utilisez des constantes et combinez des valeurs scalaires avant d'appliquer des vecteurs. Enfin, convertissez toutes les propriétés qui n'ont pas besoin d'apparaître dans l'inspecteur en tant que nœuds en ligne. Toutes ces améliorations progressives peuvent améliorer votre budget cadre.
Brancher un aperçu : À mesure que votre graphique s’agrandit, sa compilation peut devenir plus lente. Simplifiez votre flux de travail avec une branche distincte et plus petite contenant uniquement les opérations que vous souhaitez prévisualiser pour le moment. Ensuite, itérez plus rapidement sur cette branche plus petite jusqu'à ce que vous obteniez les résultats souhaités. Si la branche n'est pas connectée auMaster Node, vous pouvez laisser en toute sécurité la branche d'aperçu dans votre graphique. Unity supprime les nœuds qui n'affectent pas la sortie finale lors de la compilation.
Optimiser manuellement : Même les programmeurs graphiques expérimentés peuvent toujours utiliser un Shader Graph pour définir du code passe-partout pour un shader basé sur un script. Sélectionnez l’actifShader Graph, puis sélectionnezCopier le shaderdans le menucontextuel. Créez un nouveau shader HLSL/Cg, puis collez-le dans le Shader Graph copié. Il s'agit d'une opération à sens unique, mais elle vous permet d'obtenir des performances supplémentaires grâce à des optimisations manuelles.
Supprimez tous les shaders inutilisés de la liste appelée Shaders toujours inclus, qui se trouve dans les paramètres graphiques (Édition > Paramètres du projet > Graphiques). Ajoutez ici tous les shaders nécessaires pour la durée de vie de l'application.
Utilisez les directives pragma de compilation Shader pour adapter la compilation d'un shader à chaque plateforme cible. Utilisez ensuite un mot-clé shader (ou un nœud de mot-clé Shader Graph ) pour créer des variantes de shader avec certaines fonctionnalités activées ou désactivées.
Les variantes de shader peuvent être utiles pour les fonctionnalités spécifiques à la plate-forme, mais augmentent également les temps de construction et la taille des fichiers. Vous pouvez empêcher l’inclusion de variantes de shader dans votre build si vous savez qu’elles ne sont pas requises.
Tout d’abord, analysez le fichier Editor.log pour connaître la durée et la taille du shader. Localisez ensuite les lignes qui commencent par Compiled shader et Compressed shader.
Cet exemple de journal affiche les statistiques suivantes :
Shader compilé 'TEST Standard (configuration spéculaire)' en 31,23s
d3d9 (total des programmes internes : 482, unique : 474)
d3d11 (total des programmes internes : 482, unique : 466)
métal (total des programmes internes : 482, unique : 480)
glcore (total des programmes internes : 482, unique : 454)
Shader compressé 'TEST Standard (configuration spéculaire)' sur d3d9 de 1,04 Mo à 0,14 Mo
Shader compressé 'TEST Standard (configuration spéculaire)' sur d3d11 de 1,39 Mo à 0,12 Mo
Shader compressé 'TEST Standard (configuration spéculaire)' sur métal de 2,56 Mo à 0,20 Mo
Shader compressé 'TEST Standard (configuration spéculaire)' sur glcore de 2,04 Mo à 0,15 Mo
Ces statistiques vous disent quelques choses sur le shader :
- Il s'étend en 482 variantes grâce au#pragma multi_compileetshader_feature.
- Unity compresse le shader inclus dans les données du jeu à peu près à la somme des tailles compressées : 0,14+0,12+0,20+0,15 = 0,61 MO.
- Au moment de l'exécution, Unity conserve les données compressées en mémoire (0,61 Mo), tandis que les données de votre API graphique actuellement utilisée restent non compressées. Par exemple, si votre API actuelle est Metal, cela représenterait 2,56 Mo.
Après une construction, l' auditeur de projet (expérimental) peut analyser le fichier Editor.log pour afficher une liste de tous les shaders, mots-clés de shader et variantes de shader compilés dans le projet. Il peut également analyser le Player.log après l'exécution du jeu. Cela vous montre quelles variantes l'application a réellement compilées et utilisées au moment de l'exécution.
Utilisez ces informations pour créer un système de suppression de shader scriptable et réduire le nombre de variantes. Cela peut améliorer les temps de génération, les tailles de build et l’utilisation de la mémoire d’exécution.
Lisez l' article Suppression des variantes de shaders scriptables pour voir ce processus en détail.
L'anticrénelage contribue à une qualité d'image plus nette en réduisant les bords irréguliers et en minimisant le crénelage spéculaire.
Si vous utilisez le rendu Forward avec le pipeline de rendu intégré, l'anticrénelage multi-échantillons (MSAA) est disponible dans les paramètres de qualité . MSAA produit un anticrénelage de haute qualité, mais peut être coûteux. Le paramètre appelé MSAA Sample Count dans le menu déroulant définit le nombre d'échantillons que le moteur de rendu utilise pour évaluer l'effet (Aucun, 2X, 4X, 8X). Si vous utilisez le rendu Forward avec URP ou HDRP, vous pouvez activer MSAA sur l' actif URP ou l'actif HDRP respectivement.
Vous pouvez également ajouter un anticrénelage comme effet de post-traitement. Cela apparaît sur le composant Caméra (sous Anti-aliasing) avec quelques options :
- L'anticrénelage approximatif rapide(FXAA) lisse les bords au niveau du pixel. Il s’agit du type d’anticrénelage le moins gourmand en ressources. Cela brouille légèrement l'image finale.
- L'anticrénelage morphologique des sous-pixels(SMAA) mélange les pixels en fonction des bordures d'une image. Il offre des résultats beaucoup plus nets que FXAA et convient aux styles artistiques plats, de type dessin animé ou épurés.
En HDRP, vous pouvez également utiliser FXAA et SMAA dans l' anti-aliasing post-traitement sur la caméra avec une option supplémentaire :
- L'anticrénelage temporel(TAA) lisse les bords à l'aide des images du tampon historique. Cela fonctionne plus efficacement que FXAA mais nécessitedes vecteurs de mouvementpour fonctionner. TAA peut également améliorerl'occlusion ambianteetla volumétrie. Sa qualité est généralement supérieure à celle du FXAA, mais nécessite des ressources supplémentaires et peut produire des artefacts fantômes occasionnels.
L'option la plus rapide pour créer un éclairage est celle qui ne nécessite pas de calcul par image. Utilisez Lightmapping pour créer un éclairage statique une seule fois, au lieu de le calculer en temps réel.
Ajoutez un éclairage spectaculaire à votre géométrie statique à l'aide de l'éclairage global (GI). Cochez l'option Contribute GI pour les objets afin de stocker un éclairage de haute qualité sous forme de lightmaps.
Le processus de génération d'un environnement mappé de lumière prend plus de temps que le simple placement d'une lumière dans la scène, mais il offre des avantages clés tels que :
- Fonctionnement deux ou trois fois plus rapide pour les lumières à deux par pixel
- Visuels améliorés via Global Illumination, qui peut calculer un éclairage réaliste, direct et indirect, tandis que le lightmapper lisse et débruite la carte résultante
- Les ombres et l'éclairage ancrés sont rendus sans les performances qui résultent généralement de l'éclairage et des ombres en temps réel
Des scènes plus complexes peuvent nécessiter de longs temps de cuisson. Si votre matériel prend en charge le Progressive GPU Lightmapper (en aperçu), cette option peut considérablement accélérer la génération de votre lightmap en utilisant le GPU au lieu du CPU.
Suivez ce guide pour démarrer avec le Lightmapping dans Unity.
Bien que les sondes de réflexion puissent créer des réflexions réalistes, elles peuvent être coûteuses en termes de lots. Par conséquent, essayez ces conseils d’optimisation pour minimiser l’impact sur les performances :
- Utilisez des cubemaps basse résolution, des masques de sélection et une compression de texture pour améliorer les performances d'exécution.
- UtiliserTaper: Cuitpour éviter les mises à jour par image.
- Si l'utilisation deTaper: Temps réelest nécessaire dans URP, essayez d'éviterEvery Frameautant que possible. Ajustez les paramètresdu mode d'actualisationetdu découpage du tempspour réduire le taux de mise à jour. Vous pouvez également contrôler l'actualisation avec l'optionVia Scriptingetrestituer la sondeà partir d'un script personnalisé.
- Si l'utilisation deTaper: Temps réelest nécessaire en HDRP, sélectionnez le modeOn Demand. Vous pouvez également modifier lesparamètresdu cadredansParamètres du projet > Paramètres par défaut HDRP.
- Réduisez la qualité et les fonctionnalités sousRéflexion en temps réelpour améliorer les performances.
La projection d’ombres peut être désactivée par Mesh Renderer et la lumière. Désactivez les ombres autant que possible pour réduire les appels de tirage. Vous pouvez également créer de fausses ombres en utilisant une texture floue appliquée à un simple maillage ou quad sous vos personnages. Sinon, vous pouvez créer des ombres blob avec des shaders personnalisés.
En particulier, évitez d'activer les ombres pour les points lumineux. Chaque point lumineux avec des ombres nécessite six passes de carte d'ombre par lumière – comparez cela à une seule passe de carte d'ombre pour un spot. Envisagez de remplacer les points lumineux par des spots lorsque les ombres dynamiques sont absolument nécessaires. Si vous pouvez éviter les ombres dynamiques, utilisez plutôt un cubemap comme Light.cookie avec vos points lumineux.
Dans certains cas, vous pouvez appliquer des astuces simples plutôt que d’ajouter plusieurs lumières supplémentaires. Par exemple, au lieu de créer une lumière qui brille directement dans la caméra pour donner un effet d'éclairage Rim, utilisez un shader pour simuler l'éclairage Rim (voirles exemples de Surface Shaderpour une implémentation de ceci dans HLSL).
Pour les scènes complexes comportant de nombreuses lumières, séparez vos objets à l'aide de calques, puis limitez l'influence de chaque lumière à un masque de cullingspécifique.
Les sondes lumineuses stockent des informations d'éclairage cuites sur l'espace vide de votre scène, tout en fournissant un éclairage de haute qualité (à la fois direct et indirect). Ils utilisent des harmoniques sphériques, qui se calculent rapidement par rapport aux lumières dynamiques. Ceci est particulièrement utile pour les objets en mouvement, qui ne peuvent normalement pas recevoir le Baked Lightmapping.
Les sondes lumineuses peuvent également s’appliquer aux maillages statiques. Dans le composant Mesh Renderer , localisez le menu déroulant Recevoir l'éclairage global et faites-le basculer de Lightmaps à Light Probes.
Continuez à utiliser Lightmapping pour votre géométrie de niveau proéminente, mais passez aux sondes lumineuses pour éclairer des détails plus petits. L'éclairage de la sonde lumineuse ne nécessite pas d'UV appropriés, ce qui vous évite l'étape supplémentaire de déballer vos maillages. Les sondes réduisent également l'espace disque puisqu'elles ne génèrent pas de textures Lightmap.
Consultez l’ article Éclairage statique avec sondes lumineuses, ainsi que Création de visuels crédibles dans Unity pour plus d’informations.
L'un de nos guides les plus complets rassemble plus de 80 conseils pratiques sur la façon d'optimiser vos jeux pour PC et console. Créés par nos ingénieurs experts en Accelerate Solutions , ces conseils approfondis vous aideront à tirer le meilleur parti de Unity et à améliorer les performances de votre jeu.