Unity的URP的自定义后处理效果

概述

本来想写这个很久了,但是一直都在忙别的。

最近项目也需要用到URP的后处理,但是不一定有想要的后处理效果。所以有些还是得自己写。

但是URP的后处理和之前unity的后处理写法完全不一样了。原来的OnRenderImage、OnPreRender都失效了。

本文只探讨如何写URP下的自定义后处理,并非讨论具体的渲染效果,这里我只做了修改对比度的屏幕特效。

Unity的URP的自定义后处理效果_第1张图片Unity的URP的自定义后处理效果_第2张图片

具体实现

首先需要创建一个自定义的c#的ScriptableRendererFeature和ScriptableRenderPass的类。

然后在ScriptableRendererFeature类里写一个Setting类,并实例化它。其中 [System.Serializable]是必须的。类的命名不需要讲究。

        [System.Serializable]
        public class HLSettings
        {
            public RenderPassEvent renderPassEvent = RenderPassEvent.AfterRenderingOpaques;
            public Material mMat;
            public Target destination = Target.Color;
            public int blitMaterialPassIndex = -1;
            //这是一个shader的propertyId
            public string textureId = "_ScreenTexture";
            public float contrast = 0.5f;
        }

        public HLSettings settings = new HLSettings();

这样在PipelineAsset 点击Add Renderer Feature后,可以明显的看到setting的内容,并可以设置它们。

Unity的URP的自定义后处理效果_第3张图片

接着,在ScriptableRendererFeature的Create方法里实例化ScriptableRenderPass类。

 RenderTargetHandle m_renderTargetHandle;
 HLRenderPass m_ScriptablePass;

public override void Create()
{
     int passIndex = settings.mMat != null ? settings.mMat.passCount - 1 : 1;
     settings.blitMaterialPassIndex = Mathf.Clamp(settings.blitMaterialPassIndex, -1, passIndex);
     m_ScriptablePass = new HLRenderPass("HLPostEffectRender", settings.renderPassEvent, settings.mMat, settings.contrast);
     m_renderTargetHandle.Init(settings.textureId);
}

再接着,在AddRenderPasses方法里设置ScriptableRenderPass的source和destination的renderTarget。

public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
     var src = renderer.cameraColorTarget;
     var dest = (settings.destination == Target.Color) ? RenderTargetHandle.CameraTarget : m_renderTargetHandle;
    if (settings.mMat == null)
     {
                Debug.LogWarningFormat("丢失blit材质");
                return;
     }
     m_ScriptablePass.Setup(src,dest);
     renderer.EnqueuePass(m_ScriptablePass);
}

这样,ScriptableRendererFeature类就写好了。

接着我们写ScriptableRenderPass类。首先写它的构造函数。注意,this.renderPassEvent必须正确赋值才能保证该类在正确的RenderPassEvent的顺序下渲染。比如可以选择RenderPassEvent.AfterRenderingOpaques或者RenderPassEvent.AfterRenderingSkybox才执行该pass里的Execute方法。

public HLRenderPass(string passname, RenderPassEvent _event, Material _mat,float contrast)
{
            m_ProfilerTag = passname;
            this.renderPassEvent = _event;
            mMat = _mat;
            mMat.SetFloat("_Contrast", contrast);
            m_temporaryColorTexture.Init("temporaryColorTexture");
}

再接着,写一个接口,把source和destination的renderTarget传入进来。

        public void Setup(RenderTargetIdentifier src, RenderTargetHandle dest)
        {
            this.source = src;
            this.destination = dest;
        }

紧接着,Execute方法里执行CommandBuffer的方法,也就是以前非URP环境下的CommandBuffer写法类似。

public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
            CommandBuffer cmd = CommandBufferPool.Get(m_ProfilerTag);

            RenderTextureDescriptor opaqueDesc = renderingData.cameraData.cameraTargetDescriptor;
            opaqueDesc.depthBufferBits = 0;
            //不能读写同一个颜色target,创建一个临时的render Target去blit
            if (destination == RenderTargetHandle.CameraTarget)
            {
                cmd.GetTemporaryRT(m_temporaryColorTexture.id, opaqueDesc, filterMode);
                Blit(cmd, source, m_temporaryColorTexture.Identifier(), mMat, blitShaderPassIndex);
                Blit(cmd, m_temporaryColorTexture.Identifier(), source);
            }
            else
            {
                Blit(cmd, source, destination.Identifier(), mMat, blitShaderPassIndex);
            }
            context.ExecuteCommandBuffer(cmd);
            CommandBufferPool.Release(cmd);
}

 然后,在FrameCleanup方法里做一些释放临时资源的工作,ScriptableRenderPass类的大体处理就到这了。

        public override void FrameCleanup(CommandBuffer cmd)
        {
            if (destination == RenderTargetHandle.CameraTarget)
                cmd.ReleaseTemporaryRT(m_temporaryColorTexture.id);
        }

最后,在PipelineAsset 点击Add Renderer Feature后添加自己写的Renderer Feature,并在Settings里赋值,最重要是

材质的赋值,该材质决定了你的屏幕特效的效果是怎么渲染的。

Unity的URP的自定义后处理效果_第4张图片

温馨提示:

在Execute方法里可获取cameraData.postProcessEnabled是否生效,从而判断是否需要执行后处理效果。

 if (!renderingData.cameraData.postProcessEnabled) return;

同理,在运行游戏的时候,在Execute方法里,可以通过判断某个类的静态变量来开启或关闭自定义后处理的功能。

if(!RenderManager.OpenPostEffect)return;

代码下载:

链接:https://pan.baidu.com/s/1V85II6YYsVx_LFjWI1aseg 
提取码:gjww

参考文章:

https://github.com/Unity-Technologies/UniversalRenderingExamples

你可能感兴趣的:(shader,渲染,Unity)