Comment créer un rendu réaliste avec Unity 3D

Unity est un moteur qui par défaut vous laisse le choix, c’est une force, mais aussi un gros handicape que l’éditeur est en train de corriger avec la version 2018. Saviez qu’avec quelques efforts il est possible d’atteindre un niveau équivalent à Unreal Engine 4 ? Vous pensez que je blague et pourtant non ! C’est justement le but de cet article, vous montrer comment rendre vos jeux plus beaux avec quelques réglages et un peu de Post Processing. Unity vient d’ailleurs de sortir un guide sur le sujet, je vous recommande de récupérer le projet de démonstration pour l’étudier.

Par mesure de comparaison, je ferais l’analogie avec le moteur Unreal Engine 4 (UE4) pour vous montrer la différence qu’il peut y avoir entre les deux moteurs. Enfin cet article est réservé à un public qui connait déjà bien le moteur Unity 3D.

L’espace de couleur

Unity propose deux types de workflow pour gérer les couleurs, Linéaire ou Gamma. Pour des raisons de compatibilité c’est le mode Gamma qui était utilisé avant la version 2017.1, désormais le mode Linéaire est actif par défaut. Pour activer le profile colorimétrique Linéaire, rendez vous dans les Player Settings > Other Settings > Color Space . Mais au fait qu’est ce que ça change ?

L’avantage de l’espace colorimétrique Linéaire et qu’il donne des résultats juste, comme vous pouvez le constater sur la capture ci-dessous.

Il est important de passer dans ce mode colorimétrique pour utiliser certains effets, mais nous reviendront très vite sur ce point. Si la théorie vous intéresses, vous pouvez consulter la documentation d’Unity à ce sujet.

  • Par défaut UE4 utilise le mode colorimétrique Linéaire.

Si vous développez pour Windows Mixed Reality, vous serez confronté à un gros problème, le rendu sera très foncé dans le casque. C’est normal car Unity n’applique pas de correction Gamma sur les images envoyées au casque.. Rassurez vous, pour corriger ce problème j’ai développé un post process qui ajoute une correction Gamma et vous permet ainsi d’utiliser le mode Linéaire avec votre casque Windows Mixed Reality ! Suivez les instructions du projet sur Github.

Réglage de la caméra

Il y a deux réglages important sur la caméra, le premier va être le rendu HDR et le second dépendra de votre projet. Quand la scène est dessinée, les couleurs vont varier de 0 à 1, mais il est impossible de dessiner le rouge suivant par exemple : (Red : 10, Green : 0, Blue : 0, Alpha : 1). Activer le HDR permettra de dessiner cette couleur avec une composante rouge à 10, je vous laisse imaginer que ça va flasher sévère ! Mais à quoi cela va servir ? Pour des effets comme le Bloom, God Ray ou encore le Tone Mapping pour ne citez qu’eux. Vous allez pouvoir changer drastiquement la présence de votre rendu !

  • Par défaut les rendus UE4 sont en HDR.

Le deuxième réglage est tout simplement le type de Renderer utilisé, à savoir Forward ou Deferred ! Ne partez pas en courant 😀 vous allez adorer le Deferred Renderer et pour cause, celui-ci va vous permettre d’utiliser plusieurs dizaines de lumières en temps réel avec un coup relativement bas sur les performances. De plus ce Renderer est parfait pour utiliser certains effets comme le Screen Space Reflection !

Un peu de théorie

Le Forward Renderer

Le Forward Renderer fonctionne de manière relativement simple, voici d’ailleurs comment on peut le représenter côté code :

foreach (var light in Scene.Lights)
    foreach (var mesh in Scene.Meshes)
        foreach (var material in mesh.Materials)
            DrawMesh(mesh, material, light);

Vous comprenez mieux pourquoi il est déconseillé de mettre plus de 2 ou 3 lumières en temps réel avec un Forward Renderer ? Il est aussi évident que plus votre modèle aura de matériaux et plus le temps de rendu sera long. La complexité du Forward Renderer est O(num_geometry_fragments * num_lights).

Le Deferred Renderer

Pour le Deferred Renderer (Deferred Shading pour être exact) c’est un peu différent. On ne dessine plus la lumière en même temps que les objets. Plusieurs RenderTargets vont être créées, c’est ce que l’on appelle le G-Buffer. Le code donnerait quelque chose comme ça :

public void Draw(Camera camera, Material[] materials, Mesh[] meshes, Light[] lights)
{
    DrawShadows(camera, meshes, lights);
    SetupGBuffer();
    DrawGBuffer(materials, meshes);
    DrawLights(lights, camera.Position);
    DrawEnvironmentMap(camera);
    Compose();
}

La fonction DrawGBuffer() va dessiner sur 3 RenderTargets en même temps, une avec les objets sans lumière, une avec la profondeur (depth map) et une avec les normals (normal map). Ensuite on va dessiner les lumières dans une autre RenderTarget qu’on appelle buffer d’accumulation. La fonction Compose() va fusionner les maps pour avoir l’image finale. Grâce à une fonction interne au GPU, le Multiple Render Target (MRT). Les maps Albedo, Normal et Depth sont dessinées en même temps. Il faut que cette fonctionnalité soit supportée si vous voulez utiliser un Deferred Renderer. C’est le cas avec Direct3D9 et d’OpenGL 2.0 et OpenGL ES 3.0.

Vous pouvez constater que cette architecture est plus compliqué qu’avec un Forward Renderer, mais elle permet d’avoir beaucoup plus d’informations concernant la frame courante. Evidemment étant donné que la complexité du rendu n’est plus relatif au nombre de lumières, vous pouvez vous lâcher (mais pas trop non plus hein, car ça a quand même un coût à force) ! Attention cependant à l’ombre qui elle consommera toujours autant 😉 La complexité du Deferred Renderer est O(screen_resolution * num_lights).

Quand activer le Deferred Renderer ?

Ce Renderer est un plus gourmand que le Forward, mais dites vous bien que vous êtes en 2018, d’ailleurs si vous développez sur PC ou console Next-Gen (Xbox One, PS4), alors il n’y a pas de contre indication à son utilisation. Il n’est pas interdit de l’utiliser en VR, mais gardez en tête que la consommation GPU sera plus importante, donc si vous n’optimisez pas les choses correctement ça ira peut être un peu mal. Evidemment tout dépend de l’échelle de votre production.

Enfin il y a un dernier point noir, il ne sera pas possible d’activer le filtrage MSAA, tous vos rendus seront aliasés et il faudra impérativement avoir recourt à une solution d’antialiasing via Post Processing (FXAA, SMAA, TAA, etc…). Mais vous allez voir que c’est très simple à mettre en place alors clairement, sauf si vous avez une contre indication particulière, ne vous privez pas !

  • UE4 utilise par défaut le Deferred Renderer mais propose un Forward Renderer (conseillé pour la VR)

Scriptable RenderPipeline

Depuis Unity 2018.1, il est possible de programmer vous même votre propre boucle de rendu. Par défaut Unity propose deux nouveaux Renderers, le renderer Lightweight et HD. Les deux sont encore expérimentaux à l’heure d’écrire cet article, mais seront à privilégier dans le futur car ils offrent beaucoup plus de flexibilité, de qualité et de performances.

Le renderer Lightweight est un forward renderer optimisé pour les petites configuration, le mobile et l’AR/VR.

Le renderer HD est un forward+ renderer et/ou un Deferred Renderer avec beaucoup plus de fonctionnalités. Les composants Light sont différents, il y a plus de paramètres pour l’environnement, c’est ce qu’il faut utiliser si vous visez une production réaliste. Evidemment, elle n’est pas recommandée pour des petites configurations, mais est-ce qu’un jeu comme Battlefield ou GTAV est fait pour une petite configuration ? Clairement pas ! Donc ne vous privez pas.

Illumination Globale

Nous avons encore un point à voir avant de passer à la partie Post Processing ! Je veux évidement parler de quelque chose d’assez peu maîtrisé, l’illumination globale. Commencez par ouvrir le panneau dédié à l’éclairage : Lighting.

Le but n’est pas de vous faire un cours sur l’illumination globale car ça mériterait plusieurs articles pour être bien traité, mais si le sujet vous tient à cœur alors foncez sur cette formation vidéo. Mais je veux simplement vous informer que ce panneau existe et que suivant votre projet, il y a des cases à cocher qui pourraient bien ajouter une touche de réalisme à votre rendu. Nous allons simplement parler des modes Realtime Lighting et Mixed Lighting. D’ailleurs vous pouvez constater sur la capture que seul Realtime GI est coché. Il y a quelques temps, Unity déconseillait de cocher les deux options en même temps. Aujourd’hui ça a changé !

Un peu de théorie : Eclairage direct vs indirect

L’éclairage direct est une source de lumière active qui provient d’une source et qui rebondie contre des objets. A la différence d’un éclairage indirect qui va par exemple être la diffusion d’un matériaux sur un autre. Par exemple si vous prenez une lampe et que vous éclairez un mur, celui-ci est parfaitement éclairé et vous pouvez même constater que les objets à côté, ou même devant lui sont aussi un peu éclairés. C’est l’éclairage indirect !

Realtime GI

Ce mode d’éclairage est réservé aux configurations récentes, à savoir le PC et les consoles Next-Ge. Il permet de prendre en compte l’éclairage dynamique dans le calcul de l’éclairage indirect. Pour ce faire une série de texture vont être créées et mise à jour en live si vous changer les valeurs de vos lumières pendant l’exécution du jeu. Le moteur se servira de ces textures pour calculer l’éclairage indirect et suivant le nombre de rebond que vous aurez réglé, vous aurez un résultat plus ou moins réaliste.

Cette solution est parfaite pour être couplée avec un Deferred Renderer, mais elle a un coup en performance non négligeable je le rappel. Elle est envisageable en VR, mais là encore, sur des configurations avec de bons CPU et GPU.

Mixed GI

Vous déclarez vos lumières avec le flag Backed ou Mixed et toute la partie éclairage direct et indirect sera stockée dans une texture : La lightmap. Malheureusement vous ne pourrez faire aucun changements lorsque le jeu sera lancé, mais vous utiliserez la solution la plus performante, très largement recommandé sur mobile, mais aussi sur de gros projets VR.

Il y a cependant différents modes qui vous permettront de vous rapprocher un peu du mode Realtime GI (avec un coût en performances évidemment). Vous pouvez conserver une lumière directionnelle pseudo dynamique (mode mixed).

Indirect Multiplier

Sur vos lumières (composant Light), vous avez un champs qui se nomme Indirect Multiplier. Il permet de spécifier l’intensité de l’éclairage indirect de cette lumière. Il est très important de jouer avec cette valeur pour éclairer au mieux une scène. Evidemment il faudra backer vos lumières pour voir le résultat.

J’ai rien compris T_T j’utilise quoi ?

Tout va dépendre de votre projet et de ce que vous voulez visuellement.

Si vous travaillez sur un projet qui doit être réaliste alors voici ce que j’utiliserais

  • Toutes les lumières qui ne changent jamais ET qui ne sont pas importantes en Backed
  • Toutes les autres lumières en Mixed, cela permettra d’avoir de beaux effects spéculaires et de changer les intensités
  • Realtime + Mixed GI / Shadow Mask / avec un Deferred Renderer

Si vous voulez plutôt partir sur du mobile

  • Toutes les lumières en Backed
  • La directional en Mixed
  • Mixed GI / Subtractive / Forward Renderer

UE4 utilise un mode similaire au Mixed GI.

Light Probe et Reflection Probe

Reflection Probe

Reflection Probe

En réalité il restait ce point à étudier avant de passer au post processing. Les Reflection Probes vont permettre de capturer la reflection à 360° et d’influencer les objets qui sont dans leurs champs de vision. Avec un material bien réglé, vous pourrez avoir à moindre de coup de beaux reflets, sans avoir besoin d’une solution de post processing. Les reflets sont nécessaire pour qu’une scène soit réaliste.

  • Dans Unreal Engine ce sont les Reflection Capture

Light Probe

LightProbes

Les LightProbes c’est terriblement utile et malheureusement personne n’en parle vraiment. C’est un réseau de petites sphères qui vont capturer la couleur de les informations d’une lumière à un endroit précis. Quand un objet dynamique va passer près d’une prob, il va utiliser sa couleur comme valeur d’éclairage supplémentaire. Cela lui permet d’être cohérent avec le reste de l’environnement. Placer des probes à la main est long et fastidieux, aussi j’aimerais vous recommander deux solutions.

  • Simple Light Probe Placer est un plugin gratuit qui va placer ces probes pour vous ! Définissez une zone rectangulaire et le plugin s’occupe du reste. Malheureusement ce n’est pas ce qu’il ya  de plus optimisé, mais ça marche quand même super bien.
  • LightProbe Generator est un plugin payant qui lui aussi placera des probes automatiques, mais de manières beaucoup plus optimisées que le premier plugin.
  • Dans Unreal Engine ce sont des Lightmass Volume

Post Processing

Post Processing

Le post processing est l’étape finale et primordiale dans un rendu. C’est grâce à cela que l’on pourra avoir de l’occlusion ambiante, du bloom, etc… Unity a toujours proposé du post processing, mais en dehors de l’éditeur, à la différence d’Unreal Engine qui intègre par défaut une solution ultra complète. Depuis peu, Unity propose la PostProcessing Stack V1 et maintenant V2.

Projet HD Unity 2018.1Si vous utilisez Unity 2018.1 ou supérieur, vous pouvez utiliser le gestionnaire de paquet pour l’intégrer dans votre projet. De même vous pouvez créer un projet en utilisant le template Ultra / Lightweigth ou HD pour avoir une scène déjà toute prête avec la stack et les réglages qui vont bien ! C’est ce que fait Unreal Engine quand vous créez une nouvelle scene par exemple.

Si vous n’utiliser pas une version récente d’Unity alors il faut l’intégrer manuellement, soit en passant par l’Asset Store (version 1 à l’heure d’écrire ces lignes) soit en passant par Github. Un guide vous permettra de comprendre comment la mettre en place ici.

Enfin sachez qu’il existe d’autres solutions de post processing, je pense par exemple à Beautify qui est parfait si vous visez des configurations moyennes, ou alors le set de chez Amplify, qui dispose du meilleur Bloom que j’ai pu utiliser.

Pour finir

Nous venons de voir très grossièrement comment améliorer considérablement les rendus avec Unity 3D. L’analogie avec Unreal Engine nous a permis de constater que les deux moteurs proposent des prestations proches, mais que le premier les mets massivement en avant alors que l’autre (Unity) laisse cela au développeur. Evidemment Unity 2018 corrige cette maladresse en proposant deux nouveaux Renderers, et des templates qui eux aussi intègrent tout ce qu’il faut pour avoir un beau rendu.

Je ne peux que vous recommander de passer à Unity 2018, peut être pas d’utiliser les nouveaux Renderers si vous avez un projet existant, car vous auriez à modifier tous vos matérieux et utiliser les nouveaux shaders. Quoi qu’il en soit que vous utilisiez Unity 5.6 ou Unity 2018 vous avez de quoi faire pour que vos productions soient visuellement beaucoup plus réussies.