[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 } } }