[toc]
#  综述 
常常听说 URP 里最多只能执行一个 Pass,但这其实是不对的,为啥呢? 
就是因为 RenderFeature,URP 把实际上 Pass 执行的顺序抽象到了 CommandList 中了,即可以手动的在 C# 端控制 Pass 的执行顺序,而不需要硬写在代码里了。 
并且一个 RenderFeature 里可以执行哪些 Pass 也都是自己决定的 
接下来以毛玻璃后处理效果来记录 RenderFeature 用法
#  RenderPass 
URP14.0 后必须在 Pass 的 CameraSetup 阶段中获取 cameraColorTargetHandle , 禁止在 Feature 中获取
 
而且必须用 RTHandle  代替 RTTargetHandle
1 2 3 var  renderer = renderingData.cameraData.renderer;RenderTargetIdentifier currentRT = renderer.cameraColorTargetHandle; 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 using  System.Collections;using  System.Collections.Generic;using  UnityEngine;using  UnityEngine.Rendering;using  UnityEngine.Rendering.Universal;public  class  SFXDistortedPass  : ScriptableRenderPass {          private  RenderTargetIdentifier sourceRT;     private  Material material;     private  static  string  m_RTName = "SFXDistorted" ;     private  static  int  rtTagId = Shader.PropertyToID(m_RTName);          private  RTHandle tempRT = RTHandles.Alloc(rtTagId,name : m_RTName);     public  void  Setup (Material mat )     {         this .material = mat;     }     public  override  void  Execute (ScriptableRenderContext context, ref  RenderingData data )     {         CommandBuffer cmd = CommandBufferPool.Get("SFXDistorted22" );                  Render(cmd, ref  data);                  context.ExecuteCommandBuffer(cmd);                  CommandBufferPool.Release(cmd);     }     void  Render (CommandBuffer cmd, ref  RenderingData data )     {                  RenderTextureDescriptor opaqueDesc = data.cameraData.cameraTargetDescriptor;         opaqueDesc.depthBufferBits = 0 ;         cmd.GetTemporaryRT(rtTagId,opaqueDesc);                  cmd.Blit(sourceRT,rtTagId,material);                  cmd.Blit(rtTagId,sourceRT);     }     public  override  void  OnCameraSetup (CommandBuffer cmd, ref  RenderingData renderingData )     {         base .OnCameraSetup(cmd,ref  renderingData);         var  renderer = renderingData.cameraData.renderer;                  RenderTargetIdentifier currentRT = renderer.cameraColorTargetHandle;         sourceRT = currentRT;     }     public  override  void  OnCameraCleanup (CommandBuffer cmd )     {         base .OnCameraCleanup(cmd);         tempRT.Release();     } } 
 
#  RenderFeature 
实际的 Pass 执行都放到 context 的 EnqueuePass  中去了
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 using  System;using  System.Collections;using  System.Collections.Generic;using  UnityEngine;using  UnityEngine.Rendering;using  UnityEngine.Rendering.Universal;public  class  SFXDistortedFeature  : ScriptableRendererFeature {     [Serializable ]     public  class  DistortedSetting      {         public  RenderPassEvent Event = RenderPassEvent.AfterRenderingOpaques;         public  Shader shader;         [Tooltip("扭曲强度" ) ]         public  float  distortedInt;         [Tooltip("扭曲图" ) ]         public  Texture2D distortedTex;     }     public  DistortedSetting _settings = new  DistortedSetting();     private  Material matInstance;     private  SFXDistortedPass pass;     private  static  readonly  int  distortedInt = Shader.PropertyToID("_distortedInt" );     private  static  readonly  int  distortedTex = Shader.PropertyToID("_distortedTex" );     public  override  void  Create ()     {         pass = new  SFXDistortedPass();         pass.renderPassEvent = _settings.Event;     }     public  override  void  AddRenderPasses (ScriptableRenderer renderer, ref  RenderingData data )     {                  if  (_settings.shader == null ) return ;         if  (matInstance == null )         {             matInstance = CoreUtils.CreateEngineMaterial(_settings.shader);         }         matInstance.SetTexture(distortedTex,_settings.distortedTex);         matInstance.SetFloat(distortedInt,_settings.distortedInt);         pass.Setup(matInstance);                  renderer.EnqueuePass(pass);     } } 
 
#  设置 
#  Shader 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 Shader "URP/distortedPM"  {     Properties     {         _MainTex ("Texture" , 2 D) = "white"  {}         _BaseColor("Test Color" ,Color) = (1 ,1 ,1 ,1 )     }     SubShader     {         Pass         {             Cull Off             ZTest Always             ZWrite Off             HLSLPROGRAM             #include  "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"               #include  "Packages/com.unity.render-pipelines.core/ShaderLibrary/SpaceTransforms.hlsl"               #pragma  vertex Vertex              #pragma  fragment fragment              Texture2D _MainTex,_distortedTex;             SamplerState sampler_MainText,sampler_distortedTex;             TEXTURE2D (_CameraColorTexture);             SAMPLER (sampler_CameraColorTexture);             half4 _BaseColor;             half _distortedInt;             struct  a2v              {                 float4 vertex : POSITION;                 float2 uv : TEXCOORD0;             };             struct  v2f {                 float4 pos: SV_POSITION;                 float2 uv: TEXCOORD0;             };             v2f Vertex (a2v v)                {                v2f o;                 o.pos = TransformObjectToHClip (v.vertex);                 o.uv = v.uv;                 return  o;             }             half4 fragment (v2f i) : SV_TARGET{                  half distortedTex = _distortedTex.Sample (sampler_distortedTex, i.uv);                                  float2 uv = distortedTex*_distortedInt  + i.uv;                 return  SAMPLE_TEXTURE2D (_CameraColorTexture, sampler_CameraColorTexture, uv);             }             ENDHLSL         }     } }