Unity的URP的自定義後處理效果

概述

本來想寫這個很久了,但是一直都在忙別的。

最近項目也需要用到URP的後處理,但是不一定有想要的後處理效果。所以有些還是得自己寫。

但是URP的後處理和之前unity的後處理寫法完全不一樣了。原來的OnRenderImage、OnPreRender都失效了。

本文只探討如何寫URP下的自定義後處理,並非討論具體的渲染效果,這裏我只做了修改對比度的屏幕特效。

具體實現

首先需要創建一個自定義的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的內容,並可以設置它們。

接着,在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裏賦值,最重要是

材質的賦值,該材質決定了你的屏幕特效的效果是怎麼渲染的。

溫馨提示:

在Execute方法裏可獲取cameraData.postProcessEnabled是否生效,從而判斷是否需要執行後處理效果。

 if (!renderingData.cameraData.postProcessEnabled) return;

代碼下載:

鏈接:https://pan.baidu.com/s/1V85II6YYsVx_LFjWI1aseg 
提取碼:gjww

參考文章:

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章