在新的URP(Universal Render Pipeline)下,Unity取消了OnRenderImage函数,也就是说原来的自定义后处理的方法被取消了。而且老的Post Processing插件也失效了。URP集成了一套内置的新的后处理效果,使用起来更加方便,不过自定义起来并不简单。
自带后处理效果 在Hierarchy中新建Volume -> Global Volume;
在细节面板中新建Profile
在Add Override中就可以看到很多自带的后处理效果
然后记得把摄像机的Rendering -> Post Processing勾上
然后就能一个个玩嘞
当然也可以看看官方的教程:https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@7.1/manual/VolumeOverrides.html
自定义后处理 但是有的时候我们要使用一些自定义效果,在URP中我们可以对Volume Override进行拓展。
这里做一个简单的反转颜色看看。
准备shader URP抛弃了CG语言,只能使用hlsl进行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 60 Shader "Post Process/Invert Color" { Properties { _MainTex("Base (RGB)", 2D) = "white" {} } SubShader { Tags {"RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline"} ZTest Always Cull Off ZWrite Off Pass { Name "Invert Color" HLSLINCLUDE #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" ENDHLSL HLSLPROGRAM #pragma vertex vert #pragma fragment frag struct a2v { float4 positionOS : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; }; CBUFFER_START(UnityPerMaterial) float4 _MainTex_ST; CBUFFER_END TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); v2f vert(a2v v) { v2f o; o.pos = TransformObjectToHClip(v.positionOS.xyz); o.uv = v.uv; return o; } half4 frag(v2f i) : SV_Target { half4 color = SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex, i.uv); color = 1 - color; return color; } ENDHLSL } } }
拓展自定义Override 在Package/Universal RP/Runtime/Override文件夹下可以找到Unity自带的后处理的脚本,打开看看:
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 using System;namespace UnityEngine.Rendering.Universal { [Serializable, VolumeComponentMenu("Post-processing/Bloom" ) ] public sealed class Bloom : VolumeComponent , IPostProcessComponent { [Tooltip("Filters out pixels under this level of brightness. Value is in gamma-space." ) ] public MinFloatParameter threshold = new MinFloatParameter(0.9f , 0f ); [Tooltip("Strength of the bloom filter." ) ] public MinFloatParameter intensity = new MinFloatParameter(0f , 0f ); [Tooltip("Changes the extent of veiling effects." ) ] public ClampedFloatParameter scatter = new ClampedFloatParameter(0.7f , 0f , 1f ); [Tooltip("Clamps pixels to control the bloom amount." ) ] public MinFloatParameter clamp = new MinFloatParameter(65472f , 0f ); [Tooltip("Global tint of the bloom filter." ) ] public ColorParameter tint = new ColorParameter(Color.white, false , false , true ); [Tooltip("Use bicubic sampling instead of bilinear sampling for the upsampling passes. This is slightly more expensive but helps getting smoother visuals." ) ] public BoolParameter highQualityFiltering = new BoolParameter(false ); [Tooltip("Dirtiness texture to add smudges or dust to the bloom effect." ) ] public TextureParameter dirtTexture = new TextureParameter(null ); [Tooltip("Amount of dirtiness." ) ] public MinFloatParameter dirtIntensity = new MinFloatParameter(0f , 0f ); public bool IsActive () => intensity.value > 0f ; public bool IsTileCompatible () => false ; } }
大概能看懂,就是各种参数,直接抄一个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 using System;namespace UnityEngine.Rendering.Universal { [Serializable, VolumeComponentMenu("Addition-Post-Processing/Invert-Color" ) ] public class InvertColor : VolumeComponent , IPostProcessComponent { public BoolParameter invert = new BoolParameter(false ); public bool IsActive () { return (bool )invert; } public bool IsTileCompatible () { return false ; } } }
在Add Override中就可以找到嘞!
当然现在还没有效果,因为咱还什么都没做。
前期准备 Unity自带的后处理特效定义在Runtime/Passes的PostProcessPass.cs中,不过直接改管线不可取,所以我们可以使用RenderFeature进行扩展。
首先,为了方便管理,新建一个ScriptableObject叫AdditionPostProcessData,用于管理自定义后处理特效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 using System;using System.Collections;using System.Collections.Generic;using UnityEngine;#if UNITY_EDITOR using UnityEditor;using UnityEditor.ProjectWindowCallback;#endif using UnityEngine.Rendering.Universal;using UnityEngine.Rendering;namespace UnityEngine.Rendering.Universal { [Serializable ] public class AdditionPostProcessData : ScriptableObject { #if UNITY_EDITOR [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance" , "CA1812" ) ] [MenuItem("Assets/Create/Rendering/Universal Render Pipeline/Additional Post-process Data" , priority = CoreUtils.assetCreateMenuPriority3 + 1) ] static void CreateAdditionalPostProcessData () { var instance = CreateInstance<AdditionPostProcessData>(); AssetDatabase.CreateAsset(instance, $"Assets/Settings/{nameof (AdditionPostProcessData)} .asset" ); Selection.activeObject = instance; } #endif [Serializable ] public sealed class Shaders { public Shader invertColor = Shader.Find("Post Process/Invert Color" ); } public Shaders shaders; } }
然后创建一个MaterialLibrary对象,负责动态创建每个自定义后处理效果所需要的材质:
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 using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.Rendering;using UnityEngine.Rendering.Universal;namespace UnityEngine.Rendering.Universal { public class MaterialLibrary { public readonly Material invertColor; public MaterialLibrary (AdditionPostProcessData data ) { invertColor = Load(data.shaders.invertColor); } private Material Load (Shader shader ) { if (shader == null ) { Debug.LogErrorFormat($"Missing shader. {GetType().DeclaringType.Name} render pass will not execute. Check for missing reference in the renderer resources." ); return null ; } return shader.isSupported ? CoreUtils.CreateEngineMaterial(shader) : null ; } internal void Cleanup () { CoreUtils.Destroy(invertColor); } } }
这些都是为了后期方便处理进行的操作,下面进行Render Feature的编写。
在Render Feature中添加效果 右键 -> Rendering -> Universal Render Pipeline,新建一个Render Feature。
在下方新建一个AdditionPostProcessData的公开变量
1 public AdditionPostProcessData postData;
其中的AddRenderPasses函数需要重写,不过我们先写完ScriptableRenderPass再来写这个
在上方的ScriptableRenderPass中,我们需要重写Execute方法。我添加了SetUp和Render函数进行初始化和渲染,将反转色的效果分函数写,方便后期添加别的效果:
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 RenderTargetIdentifier m_ColorAttachment; RenderTargetHandle m_Destination; const string k_RenderPostProcessingTag = "Render AdditionalPostProcessing Effects" ;const string k_RenderFinalPostProcessingTag = "Render Final AdditionalPostProcessing Pass" ;InvertColor m_InvertColor; MaterialLibrary m_Materials; RenderTargetHandle m_TemporaryColorTexture01; RenderTargetHandle m_TemporaryColorTexture02; RenderTargetHandle m_TemporaryColorTexture03; public CustomRenderPass (AdditionPostProcessData data ){ m_Materials = new MaterialLibrary(data); m_TemporaryColorTexture01.Init("_TemporaryColorTexture1" ); m_TemporaryColorTexture02.Init("_TemporaryColorTexture2" ); m_TemporaryColorTexture03.Init("_TemporaryColorTexture3" ); } public void Setup (RenderPassEvent @event , RenderTargetIdentifier source, RenderTargetHandle destination ){ renderPassEvent = @event; m_ColorAttachment = source; m_Destination = destination; } public override void Execute (ScriptableRenderContext context, ref RenderingData renderingData ){ var stack = VolumeManager.instance.stack; m_InvertColor = stack.GetComponent<InvertColor>(); var cmd = CommandBufferPool.Get(k_RenderPostProcessingTag); Render(cmd, ref renderingData); context.ExecuteCommandBuffer(cmd); CommandBufferPool.Release(cmd); } private void Render (CommandBuffer cmd, ref RenderingData renderingData ){ ref var cameraData = ref renderingData.cameraData; if (m_InvertColor.IsActive() && !cameraData.isSceneViewCamera) { SetupInvertColor(cmd, ref renderingData, m_Materials.invertColor); } } private void SetupInvertColor (CommandBuffer cmd, ref RenderingData renderingData, Material invertMaterial ){ RenderTextureDescriptor opaqueDesc = renderingData.cameraData.cameraTargetDescriptor; cmd.GetTemporaryRT(m_TemporaryColorTexture01.id, opaqueDesc); cmd.GetTemporaryRT(m_TemporaryColorTexture02.id, opaqueDesc); cmd.GetTemporaryRT(m_TemporaryColorTexture03.id, opaqueDesc); cmd.BeginSample("invertColor" ); cmd.Blit(this .m_ColorAttachment, m_TemporaryColorTexture01.Identifier()); cmd.Blit(m_TemporaryColorTexture01.Identifier(), m_TemporaryColorTexture02.Identifier(), invertMaterial); cmd.Blit(m_TemporaryColorTexture02.Identifier(), m_ColorAttachment); cmd.Blit(m_TemporaryColorTexture02.Identifier(), this .m_Destination.Identifier()); cmd.EndSample("invertColor" ); }
然后重写AddRenderPasses函数
1 2 3 4 5 6 7 8 9 10 11 12 13 public override void Create (){ m_ScriptablePass = new CustomRenderPass(postData); m_ScriptablePass.renderPassEvent = RenderPassEvent.AfterRenderingTransparents; } public override void AddRenderPasses (ScriptableRenderer renderer, ref RenderingData renderingData ){ var cameraColorTarget = renderer.cameraColorTarget; var dest = RenderTargetHandle.CameraTarget; if (postData == null ) return ; m_ScriptablePass.Setup(cameraColorTarget, dest); renderer.EnqueuePass(m_ScriptablePass); }
配置Render Feature完成后处理效果
在Edit -> Project Settings -> Graphics -> Scriptable Render Pipeline Settings或Project Settings -> Quality -> Rendering中找到项目的UniversalRenderPipelineAsset;
在UniversalRenderPipelineAsset的细节面板的Renderer List中找到自己的RendererData;
在自己的Renderer Data细节面板中点击Add Renderer Feature,添加自己的AdditionPostProcessRenderFeature,然后画面会变黑
在在资源面板右键,Creat -> Rendering -> Universial Render Pipeline -> Additional Post-process Data创建资源,这个资源创建在Asset/Settings文件夹里,找到这个文件,并且拖入Renderer Data细节面板中New Addition PP Render Feature的Post Data属性中。
现在画面应该是正常的
点击自己的AdditionPostProcessData,细节面板中检查一下Shader的值是否被正确赋予
现在就可以正确反色嘞:
后期加入别的效果
实现shader和VolumeComponent的CS文件;
在AdditionPostProcessData和MaterialLibrary中加入新的shader;
在ScriptableRenderPass中加入材质变量、效果Setup函数,然后在Render函数中调用;
脚本控制自定义后处理效果 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 using System;using System.Collections;using System.Collections.Generic;using UnityEngine;public class PostProcessControl : MonoBehaviour { private UnityEngine.Rendering.Volume _ppv = null ; private UnityEngine.Rendering.Universal.InvertColor _invertColor = null ; private bool _invert = false ; void Start () { _ppv = GetComponent<UnityEngine.Rendering.Volume>(); if (!_ppv.profile.TryGet(out _invertColor)) { _invertColor = ScriptableObject.CreateInstance<UnityEngine.Rendering.Universal.InvertColor>(); _ppv.profile.components.Add(_invertColor); } } void Update () { if (Input.GetKeyDown(KeyCode.I)) { _invert = !_invert; } ChangeOverride(); } private void ChangeOverride () { _invertColor.invert.Override(_invert); } }
资源 https://github.com/1keven1/Unity-URP-Post-Process-Effect#readme
参考文章