LWRP(URP)学习笔记二多PASS的使用

LWRP的开篇总章中有这么一句话

The URP uses single-pass forward rendering. Use this pipeline to get optimized real-time performance on several platforms.

以及这样一张图片
在这里插入图片描述
这么没头没脑的一句话其实让很多人望而却步(也许没有很多人只是我),单pass遮挡效果怎么做?外拓描边如何实现等等?

当时内心的第一想法是不可能 肯定有办法去实现类似效果,于是找到了官方为实现类似效果做的示例 LWRP-CustomRendererExamples

看下他是如何实现遮挡显示的效果的。
LWRP(URP)学习笔记二多PASS的使用_第1张图片
这里看到他是通过指定renderertype的方式重新给rendererPipelineAssets设定一个renderData,然后看下RenderDataLWRP(URP)学习笔记二多PASS的使用_第2张图片
RenderData中默认的forwardRenderer渲染了非character层的所有东西。然后通过RendererFeatures的方式再after rendering opaques去绘制character层两次。然后在深度测试的使用决定每个像素到底是如何绘制
LWRP(URP)学习笔记二多PASS的使用_第3张图片
这是另外一个负责渲染正常character模型的RendererFeatures。

另外一个外拓描边的例子也是大同小异 通过renderFeature的方式来实现多pass。
但是个人感觉这种实现的方式不太好。可能会给GPU造成额外的压力。造成不必要的overdraw。
归根结底 这一切都是所谓的single pass导致的。因为没有更详细的说明 去源码里寻找答案

DrawObjectsPass

using System.Collections.Generic;

namespace UnityEngine.Rendering.LWRP
{
    /// 
    /// Draw  objects into the given color and depth target
    ///
    /// You can use this pass to render objects that have a material and/or shader
    /// with the pass names LightweightForward or SRPDefaultUnlit.
    /// 
    internal class DrawObjectsPass : ScriptableRenderPass
    {
        FilteringSettings m_FilteringSettings;
        RenderStateBlock m_RenderStateBlock;
        List<ShaderTagId> m_ShaderTagIdList = new List<ShaderTagId>();
        string m_ProfilerTag;
        bool m_IsOpaque;

        public DrawObjectsPass(string profilerTag, bool opaque, RenderPassEvent evt, RenderQueueRange renderQueueRange, LayerMask layerMask, StencilState stencilState, int stencilReference)
        {
            m_ProfilerTag = profilerTag;
            m_ShaderTagIdList.Add(new ShaderTagId("LightweightForward"));
            m_ShaderTagIdList.Add(new ShaderTagId("SRPDefaultUnlit"));
            renderPassEvent = evt;
            m_FilteringSettings = new FilteringSettings(renderQueueRange, layerMask);
            m_RenderStateBlock = new RenderStateBlock(RenderStateMask.Nothing);
            m_IsOpaque = opaque;

            if (stencilState.enabled)
            {
                m_RenderStateBlock.stencilReference = stencilReference;
                m_RenderStateBlock.mask = RenderStateMask.Stencil;
                m_RenderStateBlock.stencilState = stencilState;
            }
        }

        /// 
        public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
        {
            CommandBuffer cmd = CommandBufferPool.Get(m_ProfilerTag);
            using (new ProfilingSample(cmd, m_ProfilerTag))
            {
                context.ExecuteCommandBuffer(cmd);
                cmd.Clear();

                Camera camera = renderingData.cameraData.camera;
                var sortFlags = (m_IsOpaque) ? renderingData.cameraData.defaultOpaqueSortFlags : SortingCriteria.CommonTransparent;
                var drawSettings = CreateDrawingSettings(m_ShaderTagIdList, ref renderingData, sortFlags);
                context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref m_FilteringSettings, ref m_RenderStateBlock);

                // Render objects that did not match any shader pass with error shader
                RenderingUtils.RenderObjectsWithError(context, ref renderingData.cullResults, camera, m_FilteringSettings, SortingCriteria.None);
            }
            context.ExecuteCommandBuffer(cmd);
            CommandBufferPool.Release(cmd);
        }
    }
}

这里有两句代码引起了我的注意

            m_ShaderTagIdList.Add(new ShaderTagId("LightweightForward"));
            m_ShaderTagIdList.Add(new ShaderTagId("SRPDefaultUnlit"));

因为之前看过一些lwrp的shader代码 知道通过制定lightmode为LightweightForward的方式 为着色器指定渲染光照计算的pass。SRPDefaultUnlit看名字应该是给无灯光情况下使用的pass。那么如果一个shader同时有这两个pass会怎样呢?代码里我没找到答案 于是决定写一个shader试试同时存在这两个pass的shader
主要的2个pass代码如下

				// ------------------------------------------------------------------
				//  Forward pass. Shades all light in a single pass. GI + emission + Fog
				Pass
				{
				// Lightmode matches the ShaderPassName set in LightweightRenderPipeline.cs. SRPDefaultUnlit and passes with
				// no LightMode tag are also rendered by Lightweight Render Pipeline
				Name "ForwardLit"
				Tags{"LightMode" = "LightweightForward"}

				Blend[_SrcBlend][_DstBlend]
				ZWrite[_ZWrite]
				Cull[_Cull]

				HLSLPROGRAM
				// Required to compile gles 2.0 with standard SRP library
				// All shaders must be compiled with HLSLcc and currently only gles is not using HLSLcc by default
				#pragma prefer_hlslcc gles
				#pragma exclude_renderers d3d11_9x
				#pragma target 2.0

				// -------------------------------------
				// Material Keywords
				#pragma shader_feature _NORMALMAP
				#pragma shader_feature _ALPHATEST_ON
				#pragma shader_feature _ALPHAPREMULTIPLY_ON
				#pragma shader_feature _EMISSION
				#pragma shader_feature _METALLICSPECGLOSSMAP
				#pragma shader_feature _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
				#pragma shader_feature _OCCLUSIONMAP

				#pragma shader_feature _SPECULARHIGHLIGHTS_OFF
				#pragma shader_feature _ENVIRONMENTREFLECTIONS_OFF
				#pragma shader_feature _SPECULAR_SETUP
				#pragma shader_feature _RECEIVE_SHADOWS_OFF

				// -------------------------------------
				// Lightweight Pipeline keywords
				#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
				#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
				#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
				#pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS
				#pragma multi_compile _ _SHADOWS_SOFT
				#pragma multi_compile _ _MIXED_LIGHTING_SUBTRACTIVE

				// -------------------------------------
				// Unity defined keywords
				#pragma multi_compile _ DIRLIGHTMAP_COMBINED
				#pragma multi_compile _ LIGHTMAP_ON
				#pragma multi_compile_fog

				//--------------------------------------
				// GPU Instancing
				#pragma multi_compile_instancing

				#pragma vertex LitPassVertex
				#pragma fragment LitPassFragment

				#include "LitInput.hlsl"
				#include "LitForwardPass.hlsl"
				ENDHLSL
			}
			Pass
			{
				Cull Front
				ZWrite On
				ColorMask RGB
				Tags{"LightMode" = "SRPDefaultUnlit"}
				Name "OUTLINE"

				HLSLPROGRAM
				#include "Packages/com.unity.render-pipelines.lightweight/ShaderLibrary/Core.hlsl"

				#pragma vertex vert
				#pragma fragment frag
				#pragma multi_compile_fog

				CBUFFER_START(UnityPerMaterial)
				float _Outline;
				float4 _OutlineColor;
				CBUFFER_END

				struct Attributes
				{
					float4 positionOS : POSITION;
					float3 normalOS : NORMAL;
				};

				struct Varyings
				{
					float4 positionCS : SV_POSITION;
					half fogCoord : TEXCOORD0;
					half4 color : COLOR;
				};

				Varyings vert(Attributes input)
				{
					Varyings output = (Varyings)0;

					input.positionOS.xyz += input.normalOS.xyz * _Outline;

					VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
					output.positionCS = vertexInput.positionCS;

					output.color = _OutlineColor;
					output.fogCoord = ComputeFogFactor(output.positionCS.z);
					return output;
				}

				half4 frag(Varyings i) : SV_Target
				{
					i.color.rgb = MixFog(i.color.rgb, i.fogCoord);
				return _MainLightColor;
				}
				ENDHLSL
			}

LightweightForward代码基本是从litshader拷贝过来的。SRPDefaultUnlit里面也没什么特殊 只是一个法线外拓的描边。和一些没有修改回去的测试代码。代码比较好懂 但这不是重点,重点是第二个pass起效果了!LWRP(URP)学习笔记二多PASS的使用_第4张图片
所以我们在LWRP中是可以直接通过shader实现多pass的效果的。。
后期为了测试 我还添加了名为Test的lightmode pass,计算了灯光颜色等,发现都没有什么异常
也就是说 在lwrp中所谓的singlepass 只是他可以在一个pass中完成光照计算。并不是不让使用其他的pass

(以上只是自己看下来的理解,如果说错了把谁引入歧途不负责任)

你可能感兴趣的:(LWRP(URP)学习笔记)