在Unity中为LWRP创建大纲

你好

我将告诉您如何在Unity中的新轻量级渲染管线(LWRP)上创建简单的轮廓效果。 为此,您需要Unity版本2018.3和更高版本,以及LWRP版本4.0.0和更高版本。

经典轮廓由两遍着色器组成,但是LWRP仅支持单遍着色器。 为了解决LWRP中的这一缺陷,可以使用界面将自定义传递添加到渲染的某些阶段:

IAfterDepthPrePass IAfterOpaquePass IAfterOpaquePostProcess IAfterSkyboxPass IAfterTransparentPass IAfterRender 

准备工作


我们将需要两个着色器。

首先,我将使用“不亮颜色”。 相反,您可以使用另一个,主要是将Stencil构造添加到着色器。

颜色不亮
 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 } } } 


第二个是最简单的轮廓着色器本身。

简单的轮廓
 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 } } } 


自定义通行证


编写自定义通行证始于创建通常的MonoBehaviour并实现上述接口之一。 我们使用IAfterOpaquePass,因为大纲将仅应用于不透明的对象。

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

该脚本必须添加到摄像机。 通过它,我们将组织段落与游戏逻辑的交互,但以后会更多。

现在让我们开始写这段文字本身。 为此,请创建一个从ScriptableRenderPass继承的类

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

在构造函数中,我们注册通道的名称,创建材质和设置以在冷却后过滤可见对象。 在过滤器中,我们将仅设置不透明对象,因为我们将在不透明通行证之后添加通行证。

Execute函数是用于传递的渲染函数。 在其中,我们创建渲染设置,设置在构造函数中创建的材质,并渲染所有满足创建的滤镜的可见对象。

原来是我的OutlinePassImpl
 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); } } 


现在让我们添加OutlinePass类。 在这里,创建OutlinePassImpl类的实例非常简单,通过链接,您可以在运行时模式下与用户传递交互。 例如,更改轮廓颜色。

原来是我的OutlinePass
 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)); } } 


现在设置测试场景。

  1. 从SimpleColor着色器创建材质
  2. 创建一个多维数据集并将材料挂在其上。
  3. 将OutlinePass脚本添加到相机并设置颜色。
  4. 然后点击播放

轮廓仅在游戏视图中可见。

这是应该获得的结果。



奖励:友敌背光


使用用于过滤可见对象的设置,您可以指定一个图层或渲染层,以便将此段落应用于特定对象或对象组并将其与游戏逻辑关联。

更改通行证,以使所有带有“朋友”层的对象都具有绿色轮廓,而带有“敌人”层的所有对象均具有红色轮廓。

OutlinePass和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]); } } } 


在场景中,添加“朋友”和“敌人”图层,多次复制多维数据集,将它们的图层分配给“朋友”或“敌人”,设置并运行Outline Pass。



这就是我们得到的。



结论


Unity中的新渲染效果很好,可以轻松创建有趣的效果。

我希望这篇文章对阅读很有帮助。 如有任何疑问,请在评论中与您联系。

Source: https://habr.com/ru/post/zh-CN430792/


All Articles