Création d'un plan sur LWRP dans Unity

Bonjour

Je vais vous expliquer comment créer un simple effet de contour sur le nouveau pipeline de rendu léger (LWRP) dans Unity. Pour ce faire, vous avez besoin de la version Unity 2018.3 et supérieure, ainsi que de la version LWRP 4.0.0 et supérieure.

Le contour classique se compose d'un shader à deux passes, mais LWRP ne prend en charge que les shaders à passe unique. Pour corriger cet inconvénient dans LWRP, il est devenu possible d'ajouter un passage personnalisé à certaines étapes du rendu à l'aide des interfaces:

IAfterDepthPrePass IAfterOpaquePass IAfterOpaquePostProcess IAfterSkyboxPass IAfterTransparentPass IAfterRender 

La préparation


Nous aurons besoin de deux shaders.

Je vais d'abord utiliser la couleur non éclairée. Au lieu de cela, vous pouvez en utiliser un autre, l'essentiel est d'ajouter la construction Stencil au shader.

Couleur non éclairée
 Shader "Unlit/SimpleColor" { SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { Tags { "LightMode" = "LightweightForward" } Stencil { Ref 2 Comp always Pass replace } HLSLPROGRAM #pragma vertex vert #pragma fragment frag #include "Packages/com.unity.render-pipelines.lightweight/ShaderLibrary/Core.hlsl" struct appdata { float4 vertex : POSITION; }; struct v2f { float4 vertex : SV_POSITION; }; v2f vert (appdata v) { v2f o; o.vertex = TransformObjectToHClip(v.vertex.xyz); return o; } half4 frag (v2f i) : SV_Target { return half4(0.5h, 0.0h, 0.0h, 1.0h); } ENDHLSL } } } 


Le second est le shader de contour le plus simple lui-même.

Contour simple
 Shader "Unlit/SimpleOutline" { SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { Stencil { Ref 2 Comp notequal Pass keep } HLSLPROGRAM #pragma vertex vert #pragma fragment frag #include "Packages/com.unity.render-pipelines.lightweight/ShaderLibrary/Core.hlsl" struct appdata { float4 vertex : POSITION; }; struct v2f { float4 vertex : SV_POSITION; }; half4 _OutlineColor; v2f vert (appdata v) { v2f o; v.vertex.xyz += 0.2 * normalize(v.vertex.xyz); o.vertex = TransformObjectToHClip(v.vertex.xyz); return o; } half4 frag (v2f i) : SV_Target { return _OutlineColor; } ENDHLSL } } } 


Pass personnalisé


L'écriture d'une passe personnalisée commence par la création du comportement MonoBehaviour habituel et la mise en œuvre de l'une des interfaces mentionnées ci-dessus. Nous utilisons IAfterOpaquePass, car le contour ne sera appliqué qu'aux objets opaques.

 public class OutlinePass : MonoBehaviour, IAfterOpaquePass { public ScriptableRenderPass GetPassToEnqueue(RenderTextureDescriptor baseDescriptor, RenderTargetHandle colorAttachmentHandle, RenderTargetHandle depthAttachmentHandle) { //... } } 

Ce script doit être ajouté à la caméra. Et à travers lui, nous organiserons l'interaction de notre passage avec la logique du jeu, mais plus à ce sujet plus tard.

Commençons maintenant à écrire le passage lui-même. Pour ce faire, créez une classe héritée de ScriptableRenderPass

 public class OutlinePassImpl : ScriptableRenderPass { public OutlinePassImpl() { //... } public override void Execute(ScriptableRenderer renderer, ScriptableRenderContext context, ref RenderingData renderingData) { //... } } 

Dans le constructeur, nous enregistrons le nom du passage, créons des matériaux et des paramètres pour filtrer les objets visibles après refroidissement. Dans le filtre, nous ne définirons que des objets opaques, car nous ajouterons notre passe après la passe opaque.

La fonction Exécuter est une fonction de rendu pour le passage. Dans ce document, nous créons des paramètres pour le rendu, définissons le matériau créé dans le constructeur et rendons tous les objets visibles qui satisfont le filtre créé.

OutlinePassImpl qui s'est avéré à moi
 public class OutlinePassImpl : ScriptableRenderPass { private Material outlineMaterial; private FilterRenderersSettings m_OutlineFilterSettings; private int OutlineColorId; public OutlinePassImpl(Color outlineColor) { //      ,   ,    // SimpleColor RegisterShaderPassName("LightweightForward"); //   outline shader,   outlineMaterial = CoreUtils.CreateEngineMaterial("Unlit/SimpleOutline"); OutlineColorId = Shader.PropertyToID("_OutlineColor"); outlineMaterial.SetColor(OutlineColorId, outlineColor); m_OutlineFilterSettings = new FilterRenderersSettings(true) { renderQueueRange = RenderQueueRange.opaque, }; } public override void Execute(ScriptableRenderer renderer, ScriptableRenderContext context, ref RenderingData renderingData) { Camera camera = renderingData.cameraData.camera; SortFlags sortFlags = renderingData.cameraData.defaultOpaqueSortFlags; // a       DrawRendererSettings drawSettings = CreateDrawRendererSettings(camera, sortFlags, RendererConfiguration.None, renderingData.supportsDynamicBatching); drawSettings.SetOverrideMaterial(outlineMaterial, 0); context.DrawRenderers(renderingData.cullResults.visibleRenderers, ref drawSettings, m_OutlineFilterSettings); } } 


Ajoutons maintenant la classe OutlinePass. Ici, tout est très simple pour créer une instance de la classe OutlinePassImpl et via le lien, vous pouvez interagir avec le pass utilisateur en mode runtime. Par exemple, pour changer la couleur du contour.

OutlinePass qui s'est avéré à moi
 public class OutlinePass : MonoBehaviour, IAfterOpaquePass { public Color OutlineColor; private OutlinePassImpl outlinePass; public ScriptableRenderPass GetPassToEnqueue(RenderTextureDescriptor baseDescriptor, RenderTargetHandle colorAttachmentHandle, RenderTargetHandle depthAttachmentHandle) { return outlinePass ?? (outlinePass = new OutlinePassImpl(OutlineColor)); } } 


Maintenant, configurez la scène pour le test.

  1. Créer un matériau à partir du nuanceur SimpleColor
  2. Créez un cube et accrochez-y du matériel.
  3. Ajoutez un script OutlinePass à la caméra et définissez la couleur.
  4. Et cliquez sur jouer

Le contour ne sera visible que dans la vue du jeu.

Voici le résultat à obtenir.



Bonus: rétro-éclairage ami-ennemi


En utilisant le paramètre de filtrage des objets visibles, vous pouvez spécifier un calque ou un calque de rendu afin d'appliquer ce passage à un objet ou un groupe d'objets spécifique et l'associer à la logique du jeu.

Modifiez notre passe de sorte que tous les objets avec le calque "Friend" aient un contour vert, et avec le calque "Enemy" rouge.

OutlinePass et OutlinePassImpl
 public class OutlinePass : MonoBehaviour, IAfterOpaquePass { [System.Serializable] public class OutlineData { public Color Color; public LayerMask Layer; } public List<OutlineData> outlineDatas = new List<OutlineData>(); private OutlinePassImpl outlinePass; public ScriptableRenderPass GetPassToEnqueue(RenderTextureDescriptor baseDescriptor, RenderTargetHandle colorAttachmentHandle, RenderTargetHandle depthAttachmentHandle) { return outlinePass ?? (outlinePass = new OutlinePassImpl(outlineDatas)); } } public class OutlinePassImpl : ScriptableRenderPass { private Material[] outlineMaterial; private FilterRenderersSettings[] m_OutlineFilterSettings; public OutlinePassImpl(List<OutlinePass.OutlineData> outlineDatas) { RegisterShaderPassName("LightweightForward"); outlineMaterial = new Material[outlineDatas.Count]; m_OutlineFilterSettings = new FilterRenderersSettings[outlineDatas.Count]; Shader outlineShader = Shader.Find("Unlit/SimpleOutline"); int OutlineColorId = Shader.PropertyToID("_OutlineColor"); for (int i = 0; i < outlineDatas.Count; i++) { OutlinePass.OutlineData outline = outlineDatas[i]; Material material = CoreUtils.CreateEngineMaterial(outlineShader); material.SetColor(OutlineColorId, outline.Color); outlineMaterial[i] = material; m_OutlineFilterSettings[i] = new FilterRenderersSettings(true) { renderQueueRange = RenderQueueRange.opaque, layerMask = outline.Layer }; } } public override void Execute(ScriptableRenderer renderer, ScriptableRenderContext context, ref RenderingData renderingData) { Camera camera = renderingData.cameraData.camera; SortFlags sortFlags = renderingData.cameraData.defaultOpaqueSortFlags; DrawRendererSettings drawSettings = CreateDrawRendererSettings(camera, sortFlags, RendererConfiguration.None, renderingData.supportsDynamicBatching); for (int i = 0; i < outlineMaterial.Length; i++) { drawSettings.SetOverrideMaterial(outlineMaterial[i], 0); context.DrawRenderers(renderingData.cullResults.visibleRenderers, ref drawSettings, m_OutlineFilterSettings[i]); } } } 


Sur la scène, ajoutez les couches "Friend" et "Enemy", dupliquez le cube plusieurs fois, affectez-les à "Friend" ou "Enemy", définissez le Pass Outline et exécutez-le.



Et c'est ce que nous obtenons.



Conclusion


Le nouveau rendu dans Unity se développe très bien, ce qui rend la création d'effets intéressants très facile.

J'espère que l'article a été utile à la lecture. Si quelqu'un a des questions, rendez-vous dans les commentaires.

Source: https://habr.com/ru/post/fr430792/


All Articles