Guten Tag.
Ich werde Ihnen erklären, wie Sie einen einfachen Gliederungseffekt für die neue Lightweight Render Pipeline (LWRP) in Unity erstellen. Dazu benötigen Sie Unity Version 2018.3 und höher sowie LWRP Version 4.0.0 und höher.
Die klassische Gliederung besteht aus einem Zwei-Pass-Shader, aber LWRP unterstützt nur Single-Pass-Shader. Um diesen Nachteil in LWRP zu beheben, wurde es möglich, bestimmten Phasen des Renderns über Schnittstellen einen benutzerdefinierten Durchgang hinzuzufügen:
IAfterDepthPrePass IAfterOpaquePass IAfterOpaquePostProcess IAfterSkyboxPass IAfterTransparentPass IAfterRender
Vorbereitung
Wir brauchen zwei Shader.
Zuerst werde ich Unlit Color verwenden. Stattdessen können Sie eine andere verwenden. Die Hauptsache ist, das Stencil-Konstrukt zum Shader hinzuzufügen.
Unbeleuchtete Farbe 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 } } }
Der zweite ist der einfachste Gliederungs-Shader.
Einfache Gliederung 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 } } }
Benutzerdefinierter Pass
Das Schreiben eines benutzerdefinierten Passes beginnt mit dem Erstellen des üblichen MonoBehaviour und dem Implementieren einer der oben genannten Schnittstellen. Wir verwenden IAfterOpaquePass, da Konturen nur auf undurchsichtige Objekte angewendet werden.
public class OutlinePass : MonoBehaviour, IAfterOpaquePass { public ScriptableRenderPass GetPassToEnqueue(RenderTextureDescriptor baseDescriptor, RenderTargetHandle colorAttachmentHandle, RenderTargetHandle depthAttachmentHandle) {
Dieses Skript muss der Kamera hinzugefügt werden. Und dadurch werden wir die Interaktion unserer Passage mit der Spielelogik organisieren, aber dazu später mehr.
Beginnen wir nun damit, die Passage selbst zu schreiben. Erstellen Sie dazu eine von ScriptableRenderPass geerbte Klasse
public class OutlinePassImpl : ScriptableRenderPass { public OutlinePassImpl() {
Im Konstruktor registrieren wir den Namen der Passage, erstellen Material und Einstellungen zum Filtern sichtbarer Objekte nach dem Abkühlen. Im Filter setzen wir nur undurchsichtige Objekte, da wir unseren Durchgang nach dem undurchsichtigen Durchgang hinzufügen.
Die Execute-Funktion ist eine Renderfunktion zum Übergeben. Darin erstellen wir Einstellungen für das Rendern, legen das im Konstruktor erstellte Material fest und rendern alle sichtbaren Objekte, die dem erstellten Filter entsprechen.
OutlinePassImpl, das sich bei mir herausstellte public class OutlinePassImpl : ScriptableRenderPass { private Material outlineMaterial; private FilterRenderersSettings m_OutlineFilterSettings; private int OutlineColorId; public OutlinePassImpl(Color outlineColor) {
Fügen wir nun die OutlinePass-Klasse hinzu. Hier ist alles sehr einfach, um eine Instanz der OutlinePassImpl-Klasse zu erstellen, und über den Link können Sie im Laufzeitmodus mit dem Benutzerpass interagieren. Zum Beispiel, um die Umrissfarbe zu ändern.
OutlinePass, der sich bei mir herausstellte 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)); } }
Richten Sie nun die Szene für den Test ein.
- Erstellen Sie Material aus dem SimpleColor Shader
- Erstellen Sie einen Würfel und hängen Sie Material daran.
- Fügen Sie der Kamera ein OutlinePass-Skript hinzu und legen Sie die Farbe fest.
- Und klicken Sie auf Wiedergabe
Die Gliederung wird nur in der Spielansicht angezeigt.
Hier sollte das Ergebnis erhalten werden.

Bonus: Freund-Feind-Hintergrundbeleuchtung
Mit der Einstellung zum Filtern sichtbarer Objekte können Sie eine Ebene oder eine Renderebene angeben, um diese Passage auf ein bestimmtes Objekt oder eine bestimmte Gruppe von Objekten anzuwenden und sie der Spiellogik zuzuordnen.
Ändern Sie unseren Pass so, dass alle Objekte mit der Ebene "Freund" einen grünen Umriss und mit der Ebene "Feind" rot haben.
OutlinePass und 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]); } } }
Fügen Sie in der Szene die Ebenen "Freund" und "Feind" hinzu, duplizieren Sie den Würfel mehrmals, weisen Sie sie den Ebenen "Freund" oder "Feind" zu, legen Sie den Gliederungspass fest und führen Sie ihn aus.

Und das bekommen wir.

Fazit
Das neue Rendering in Unity wird sehr gut erweitert, was das Erstellen interessanter Effekte sehr einfach macht.
Ich hoffe, der Artikel war nützlich zum Lesen. Wenn jemand Fragen hat, sehen wir uns in den Kommentaren.