URP屏幕后處理

URP屏幕后處理

由于Unity對URP的屏幕后處理需集成要到2019.4版本后才穩(wěn)定,所以升級Unity版本到2019.4.9

Post Processing

在創(chuàng)建我們自己屏幕后處理系統(tǒng)前,我們需要先學會使用UnityURP管線中集成的屏后處理系統(tǒng)。

低于Unity2019.4版本的URP是沒有Volume組件的

  1. 我們可以將Volume組件添加到GameObject,或者在Hierarchy面板中中右鍵單擊并在Volume標題下選擇某些內(nèi)容。

    • Global Volume代表后處理效果應用所有攝像機
    • Box Volume會在場景中創(chuàng)建一個盒子區(qū)域(該區(qū)域在Scene中用BoxCollider組件顯示輪廓),只有攝像機進入該區(qū)域才會應用后處理效果
    • Sphere Volume是一個球形區(qū)域,效果同上
    • Convex Mesh Volume允許我們使用自定義的網(wǎng)格區(qū)域
  2. Volume組件上有如下參數(shù)

    屬性 描述
    Mode Global:使Volume無邊界并影響場景中的每一個攝像機。 Local:為Volume指定邊界,Volume只影響在邊界內(nèi)部的射線機。
    Blend Distance URP從Volume Collider開始融合的最遠距離。0表示URP立即應用Volume的Override;該屬性只有在非Global Volume下才出現(xiàn)
    Weight Volume在場景中的影響值
    Priority 當Volume在場景中有多個Volume時,URP通過此值決定使用哪一個Volume。URP優(yōu)先使用priority更高的
    Profile Profile Asset存儲URP處理Volume的數(shù)據(jù)
  3. 點擊Profile旁的New按鈕,新建一個后處理配置文件,然后我們就可以通過Add Override添加各種URP內(nèi)置后處理效果了。

    有關(guān)URP后處理效果清單見https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@8.0/manual/EffectList.html

  4. 當我們?yōu)榕渲梦募砑由钚Ч?strong>Chromatic Aberration,并開啟效果后會發(fā)現(xiàn),在Scene視圖中已經(jīng)出現(xiàn)了效果,但在Game視圖中卻沒有任何變化。

    接下來我們需要將場景中的攝像機開啟屏幕后處理,選中場景中攝像機,在Inspector面板中找到Rendering欄下的Post Processing開關(guān),勾選上。

    現(xiàn)在Game中已經(jīng)出現(xiàn)效果

這里列出URP中可用的后處理效果

  • 高光(Bloom)高光效果從圖片中的光亮部分的邊緣長生羽毛形狀的光。并且產(chǎn)生遮擋。Bloom中有一個Lens Dirt特征,這個可以用于產(chǎn)生全屏光斑。
  • 通道混合器(Channel Mixer):通道混合器提供每個顏色通道的信息,通過調(diào)整不同通道的影響可以實現(xiàn)不同的屏幕效果。
  • 色差(Chromatic Aberration):仿真實現(xiàn)了真實攝像機無法將所有顏色融合到一個點。
  • 顏色調(diào)整(Color Adjustments) 調(diào)整整體的色調(diào)、亮度和對比度
  • 顏色曲線(Color Curves):通過曲線的方式調(diào)整色相、飽和度或者亮度。
  • 景深(Depth Of Field): 景深組件模擬相機鏡頭的聚焦特性。現(xiàn)實生活中,相機只能對特定距離清晰對焦。距離攝像機較遠和較近的物體無法聚焦。根據(jù)模糊效果引入了Bokeh(散景),Bokeh指當圖像失焦時出現(xiàn)在明亮區(qū)域的視覺偽像。
  • 膠片顆粒(Film Grain):Film Grain是加工攝影膠片的隨機光學紋理,因為存在鹵化銀產(chǎn)生的金屬銀或染料云的小顆粒,其已經(jīng)接收到了足夠的光子。
  • 鏡頭變形(Lens Distortion):扭曲圖片模擬真實的鏡頭
  • 提升伽馬增益(Lift Gamma Gain):調(diào)整圖像的lift、Gamma、Gain
  • 運動模糊(Motion Blur):模擬真實攝像機在拍攝運動物體時,運動速度大于曝光時間的時候出現(xiàn)的模糊效果。
  • 帕尼尼投影(Panini Projection):一種圓柱形投影,保持垂直方向上的垂直,在渲染大視角的時候提供更好的效果。視角120度無后處理。
  • 陰影 中間色調(diào) 高光(Shadows Midtones Hightlights):使用圓環(huán)工具進行三個熟知的調(diào)整
  • 分割色調(diào)(Split Toning):根據(jù)亮度值對不同的區(qū)域進行著色,幫助我們實現(xiàn)更加獨特的視覺效果。可以通過此效果實現(xiàn)陰影和高光部分不同的色調(diào)。
  • 色調(diào)映射(Tonemapping):在屏幕上重新映射HDR的過程
  • 玩具相機(Vignette):暗角效果和去飽和,現(xiàn)實中造成這種結(jié)果的原因通常是堆疊濾鏡,輔助鏡片和不當?shù)恼诠庹帧?/li>
  • 白平衡(White Balance):應用白平衡組件,消除不真實的偏色,從而使白色在圖像中呈現(xiàn)白色。我們也可以用來呈現(xiàn)冷色或者暖色的渲染效果。

擴展Volume

既然我們已經(jīng)學會了如何使用Volume組件,那么我們接下來所需做的就是如何去擴展該組件,增加我們的屏幕后處理效果。

解讀Volume運作

首先我們可以在URP包目錄下的com.unity.render-pipelines.universal@7.5.1\Runtime\Overrides文件夾中找到,包含了所有為Volume配置文件添加的效果的屬性腳本。為方便做比較,我們打開目錄中的Bloom腳本,可以發(fā)現(xiàn)腳本中只有屬性,且這些屬性名對應了Volume組件中的效果屬性。

然后我們可以找到一個文件com.unity.render-pipelines.universal@7.5.1\Runtime\Passes\PostProcessPass.cs,這個PostProcessPass就是URP內(nèi)置后處理的核心,它繼承了ScriptableRenderPass,方便在URP管線下擴展額外的Pass通道。

所有繼承ScriptableRenderPass組件的子類需要實現(xiàn)一個方法:

public abstract void Execute(ScriptableRenderContext context, ref RenderingData renderingData);

其實該方法的作用和我們在Built-in管線下寫后處理框架時用到的oid OnRenderImage(RenderTexture src, RenderTexture dest)方法功能是一樣的,在每幀渲染,渲染管線都會調(diào)用該方法。然后我們會在該方法里通過Shader的Pass進行后處理。

其中的ScriptableRenderContext 參數(shù)我們在前面SRP嘗試章節(jié)里已經(jīng)見識過,它是定義自定義渲染管道使用的狀態(tài)和繪制命令,使用該參數(shù)我們可以進行額外的Pass繪制。RenderingData也好理解,就是當前調(diào)用該方法的繪制信息,其中包含調(diào)用該次繪制的相機信息、光源信息、陰影信息等;注意,該參數(shù)帶有ref關(guān)鍵字,說明我們是可以直接對這些繪制信息進行修改,并影響后續(xù)管線的成像的。

可編程渲染功能

從前面URP源代碼可以看出,其實URP的后處理方式和Built-in管線下的后處理方式思路相同,都是通過C#代碼去調(diào)用Shader進行后處理。但有一點不同,在Built-in管線下,后處理腳本我們是繼承Mono的,直接將腳本掛在對象上就可運作(mono自動調(diào)用OnRenderImage方法);但是URP下繼承的是ScriptableRenderPass,該類是一個對象,我們由如何讓他運作呢。

在我們URP管線的Inspector面板下,RendererList中有我們當前真正使用的渲染器列表,

跳轉(zhuǎn)到使用渲染器的Inspector面板后我們可以看到Post ProcessData,Post ProcessData正是URP用于引用各種后處理Shader的對象。

而下方的Rederer Features則是我們的重點,它允許我們添加額外的渲染功能,也就是我們可以寫一個功能腳本,在腳本中創(chuàng)建我們自定義的ScriptableRenderPass對象,然后添加到該列表中,后續(xù)URP管線在渲染過程中會自動調(diào)用該功能,也就是間接調(diào)用我們自定義的后處理對象,以此實現(xiàn)URP管線下的自定義后處理。

想要編寫額外的渲染功能,我們需要將腳本繼承ScriptableRendererFeature,并且實現(xiàn)AddRenderPassesCreate函數(shù)。Create方法會在該功能初始化時調(diào)用,我們可以在方法中創(chuàng)建我們的后處理對象。AddRenderPasses將會在相機被設置渲染器時調(diào)用。

調(diào)整屏幕亮度、飽和度、對比度

既然運作方式解析了,那么進入實操環(huán)節(jié)。

創(chuàng)建Shader

創(chuàng)建Shader-Brightness Saturation And Contrast,該Shader比較簡單,沒有什么新的語法。

在不知道該Shader是否正確的情況下,可以創(chuàng)建一個Plane拖入到攝像機視野內(nèi)(這很重要),再創(chuàng)建該Shader的材質(zhì),將材質(zhì)賦給Palne。最后再給材質(zhì)添加紋理,調(diào)整不同的參數(shù),在Game中看效果是否正確。

Shader "URP/Brightness Saturation And Contrast"
{
    Properties
    {
        // 基礎紋理
        _MainTex ("Base (RGB)", 2D) = "white" { }
        // 亮度
        _Brightness ("Brightness", Float) = 1
        // 飽和度
        _Saturation ("Saturation", Float) = 1
        // 對比度
        _Contrast ("Contrast", Float) = 1
    }
    SubShader
    {
        Tags { "RenderPipeline" = "UniversalPipeline" }
        
        HLSLINCLUDE
        #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
        
        CBUFFER_START(UnityPerMaterial)
        float4 _MainTex_ST;
        half _Brightness;
        half _Saturation;
        half _Contrast;
        CBUFFER_END
        
        ENDHLSL
        
        Pass
        {
            // 開啟深度測試 關(guān)閉剔除 關(guān)閉深度寫入
            ZTest Always Cull Off ZWrite Off
            
            HLSLPROGRAM
            
            #pragma vertex vert
            #pragma fragment frag
            
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            
            // 聲明紋理
            TEXTURE2D(_MainTex);
            // 聲明采樣器
            SAMPLER(sampler_MainTex);
            
            struct a2v
            {
                float4 vertex: POSITION;
                
                float4 texcoord: TEXCOORD0;
            };
            
            struct v2f
            {
                float4 pos: SV_POSITION;
                half2 uv: TEXCOORD0;
            };
            
            v2f vert(a2v v)
            {
                v2f o;
                
                o.pos = TransformObjectToHClip(v.vertex.xyz);
                
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                
                return o;
            }
            
            half4 frag(v2f i): SV_Target
            {
                // 紋理采樣
                half4 renderTex = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
                
                // 調(diào)整亮度 = 原顏色 * 亮度值
                half3 finalColor = renderTex.rgb * _Brightness;
                
                // 調(diào)整飽和度
                // 亮度值(飽和度為0的顏色) = 每個顏色分量 * 特定系數(shù)
                half luminance = 0.2125 * renderTex.r + 0.7154 * renderTex.g + 0.0721 * renderTex.b;
                half3 luminanceColor = half3(luminance, luminance, luminance);
                // 插值亮度值和原圖
                finalColor = lerp(luminanceColor, finalColor, _Saturation);
                
                // 調(diào)整對比度
                // 對比度為0的顏色
                half3 avgColor = half3(0.5, 0.5, 0.5);
                finalColor = lerp(avgColor, finalColor, _Contrast);
                
                return half4(finalColor, renderTex.a);
            }            
            ENDHLSL            
        }
    }
    
    Fallback Off
}

創(chuàng)建屬性參數(shù)腳本

  1. 編寫類BrightnessSaturationContrast繼承VolumeComponent組件和IPostProcessComponent接口,用以繼承Volume框架。

  2. 在方法中我們根據(jù)材質(zhì)所需的三個參數(shù)亮度、飽和度、對比度創(chuàng)建三個屬性。

            public ClampedFloatParameter brightness = new ClampedFloatParameter(0f, 0, 3);
            public ClampedFloatParameter saturation = new ClampedFloatParameter(0f, 0, 3);
            public ClampedFloatParameter contrast = new ClampedFloatParameter(0f, 0, 3);
    

創(chuàng)建可編程渲染Pass腳本

  1. 創(chuàng)建C#腳本AdditionPostProcessPass,繼承自ScriptableRenderPass,并實現(xiàn)Execute方法。

  2. 創(chuàng)建所需屬性

            //標簽名,用于續(xù)幀調(diào)試器中顯示緩沖區(qū)名稱
            const string CommandBufferTag = "AdditionalPostProcessing Pass";
        
            // 用于后處理的材質(zhì)
            public Material m_Material;
    
            // 屬性參數(shù)組件
            BrightnessSaturationContrast m_BrightnessSaturationContrast;
    
            // 顏色渲染標識符
            RenderTargetIdentifier m_ColorAttachment;
            // 臨時的渲染目標
            RenderTargetHandle m_TemporaryColorTexture01;
    
  3. 創(chuàng)一個入口函數(shù),用于后續(xù)渲染管線功能腳本寫入?yún)?shù)

            // 設置渲染參數(shù)
            public void Setup(RenderTargetIdentifier _ColorAttachment, Material Material)
            {
                this.m_ColorAttachment = _ColorAttachment;
    
                m_Material = Material;
            } 
    
  4. 修改Execute方法,在方法中我們通過VolumeManager.instance.stack單例獲取Volume框架中所有的堆棧,在從堆棧中獲取我們上一部創(chuàng)建的屬性參數(shù)組件,由于Execute是每幀調(diào)用,所有該組件也是實時更新的。

    然后我們使用標簽名獲取一個命令緩沖區(qū),將該命令緩沖區(qū)與Execute的參數(shù)RenderingData渲染信息一起交給Render方法進行后處理。

    在后處理完成后我們調(diào)用context.ExecuteCommandBuffer(cmd);方法執(zhí)行該命令緩沖區(qū),最后釋放內(nèi)存。

            public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
            {
                // 從Volume框架中獲取所有堆棧
                var stack = VolumeManager.instance.stack;
                // 從堆棧中查找對應的屬性參數(shù)組件
                m_BrightnessSaturationContrast = stack.GetComponent<BrightnessSaturationContrast>();
    
                // 從命令緩沖區(qū)池中獲取一個帶標簽的命令緩沖區(qū),該標簽名可以在后續(xù)幀調(diào)試器中見到
                var cmd = CommandBufferPool.Get(CommandBufferTag);
    
                // 調(diào)用渲染函數(shù)
                Render(cmd, ref renderingData);
    
                // 執(zhí)行命令緩沖區(qū)
                context.ExecuteCommandBuffer(cmd);
                // 釋放命令緩存
                CommandBufferPool.Release(cmd);
                // 釋放臨時RT
                cmd.ReleaseTemporaryRT(m_TemporaryColorTexture01.id);
            }
    
  5. 接下來我們編寫渲染方法Render,在Render方法中我們獲取屬性參數(shù)組件中的參數(shù),賦值給材質(zhì)。

    然后通過RenderingData對象中的相機信息創(chuàng)建一個臨時緩沖區(qū),然后將顏色渲染器中的顏色通過Shader進行計算后保存到臨時緩沖區(qū)中。

    最后在從臨時緩沖區(qū)中讀取出來返還到主紋理中。

         // 渲染
         void Render(CommandBuffer cmd, ref RenderingData renderingData)
         {       
             // VolumeComponent是否開啟,且非Scene視圖攝像機
             if (m_BrightnessSaturationContrast.IsActive() && !renderingData.cameraData.isSceneViewCamera)
             {
                 // 寫入?yún)?shù)
                 m_Material.SetFloat("_Brightness", m_BrightnessSaturationContrast.brightness.value);
                 m_Material.SetFloat("_Saturation", m_BrightnessSaturationContrast.saturation.value);
                 m_Material.SetFloat("_Contrast", m_BrightnessSaturationContrast.contrast.value);
    
                 // 獲取目標相機的描述信息
                 RenderTextureDescriptor opaqueDesc = renderingData.cameraData.cameraTargetDescriptor;
                 // 設置深度緩沖區(qū)
                 opaqueDesc.depthBufferBits = 0;
                 // 通過目標相機的渲染信息創(chuàng)建臨時緩沖區(qū)
                 cmd.GetTemporaryRT(m_TemporaryColorTexture01.id, opaqueDesc);
    
                 // 通過材質(zhì),將計算結(jié)果存入臨時緩沖區(qū)
                 cmd.Blit(m_ColorAttachment, m_TemporaryColorTexture01.Identifier(), m_Material);
                 // 再從臨時緩沖區(qū)存入主紋理
                 cmd.Blit(m_TemporaryColorTexture01.Identifier(), m_ColorAttachment);
             }
    

創(chuàng)建可編程渲染功能腳本

  1. 創(chuàng)建類AdditionPostProcessRendererFeature,繼承ScriptableRendererFeature抽象類,并實現(xiàn)AddRenderPassesCreate方法

  2. 設置三個參數(shù),公開屬性Shader、私有屬性AdditionPostProcessPass對象和材質(zhì)

            // 用于后處理的Shader 
            public Shader shader;
            // 后處理Pass
            AdditionPostProcessPass postPass;
            // 根據(jù)Shader生成的材質(zhì)
            Material _Material=null;
    
  3. 修改Create方法,在方法中創(chuàng)建AdditionPostProcessPass對象,并修改該類的渲染時機,在透明物體渲染后。

  4. 修改AddRenderPasses方法,在方法中通過Shader創(chuàng)建材質(zhì),然后從ScriptableRenderer參數(shù)中獲取主紋理;接下來將紋理和材質(zhì)傳入AdditionPostProcessPass對象中,最后將該對象添加到渲染管線隊列中。

            public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
            {
                // 檢測Shader是否存在
                if (shader == null)
                    return;
    
                // 創(chuàng)建材質(zhì)
                if (_Material==null)
                    _Material = CoreUtils.CreateEngineMaterial(shader);
    
                // 獲取當前渲染相機的目標顏色,也就是主紋理
                var cameraColorTarget = renderer.cameraColorTarget;     
    
                // 設置調(diào)用后處理Pass
                postPass.Setup(cameraColorTarget, _Material);
                
                // 添加該Pass到渲染管線中
                renderer.EnqueuePass(postPass);
            }
    

配置管線

  1. 配置Volume組件,將BrightnessSaturationContrast屬性參數(shù)組件添加到效果列表中

  2. 配置管線,在URP管線的配置文件中添加我們編寫的渲染功能AdditionPostProcessRendererFeature

  3. 賦值Shader

  4. 修改屬性參數(shù)組件的參數(shù),以降低飽和度

完整代碼

Shader——Brightness Saturation And Contrast

Shader "URP/Brightness Saturation And Contrast"
{
    Properties
    {
        // 基礎紋理
        _MainTex ("Base (RGB)", 2D) = "white" { }
        // 亮度
        _Brightness ("Brightness", Float) = 1
        // 飽和度
        _Saturation ("Saturation", Float) = 1
        // 對比度
        _Contrast ("Contrast", Float) = 1
    }
    SubShader
    {
        Tags { "RenderPipeline" = "UniversalPipeline" }
        
        HLSLINCLUDE
        #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
        
        CBUFFER_START(UnityPerMaterial)
        float4 _MainTex_ST;
        half _Brightness;
        half _Saturation;
        half _Contrast;
        CBUFFER_END
        
        ENDHLSL
        
        Pass
        {
            // 開啟深度測試 關(guān)閉剔除 關(guān)閉深度寫入
            ZTest Always Cull Off ZWrite Off
            
            HLSLPROGRAM
            
            #pragma vertex vert
            #pragma fragment frag
            
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            
            // 聲明紋理
            TEXTURE2D(_MainTex);
            // 聲明采樣器
            SAMPLER(sampler_MainTex);
            
            struct a2v
            {
                float4 vertex: POSITION;
                
                float4 texcoord: TEXCOORD0;
            };
            
            struct v2f
            {
                float4 pos: SV_POSITION;
                half2 uv: TEXCOORD0;
            };
            
            v2f vert(a2v v)
            {
                v2f o;
                
                o.pos = TransformObjectToHClip(v.vertex.xyz);
                
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                
                return o;
            }
            
            half4 frag(v2f i): SV_Target
            {
                // 紋理采樣
                half4 renderTex = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
                
                // 調(diào)整亮度 = 原顏色 * 亮度值
                half3 finalColor = renderTex.rgb * _Brightness;
                
                // 調(diào)整飽和度
                // 亮度值(飽和度為0的顏色) = 每個顏色分量 * 特定系數(shù)
                half luminance = 0.2125 * renderTex.r + 0.7154 * renderTex.g + 0.0721 * renderTex.b;
                half3 luminanceColor = half3(luminance, luminance, luminance);
                // 插值亮度值和原圖
                finalColor = lerp(luminanceColor, finalColor, _Saturation);
                
                // 調(diào)整對比度
                // 對比度為0的顏色
                half3 avgColor = half3(0.5, 0.5, 0.5);
                finalColor = lerp(avgColor, finalColor, _Contrast);
                
                return half4(finalColor, renderTex.a);
            }            
            ENDHLSL            
        }
    }
    
    Fallback Off
}

BrightnessSaturationContrast

using System;

// 通用渲染管線程序集
namespace UnityEngine.Rendering.Universal
{
    // 實例化類     添加到Volume組件菜單中
    [Serializable, VolumeComponentMenu("Addition-Post-processing/BrightnessSaturationContrast")]
    // 繼承VolumeComponent組件和IPostProcessComponent接口,用以繼承Volume框架
    public class BrightnessSaturationContrast : VolumeComponent, IPostProcessComponent
    {
        // 在框架下的屬性與Unity常規(guī)屬性不一樣,例如 Int 由 ClampedIntParameter 取代。
        public ClampedFloatParameter brightness = new ClampedFloatParameter(0f, 0, 3);
        public ClampedFloatParameter saturation = new ClampedFloatParameter(0f, 0, 3);
        public ClampedFloatParameter contrast = new ClampedFloatParameter(0f, 0, 3);
        // 實現(xiàn)接口
        public bool IsActive()
        {
            return active;
        }

        public bool IsTileCompatible()
        {
            return false;
        }
    }
}

AdditionPostProcessPass

namespace UnityEngine.Rendering.Universal
{
    /// <summary>
    /// 附加的后處理Pass
    /// </summary>
    public class AdditionPostProcessPass : ScriptableRenderPass
    {
        //標簽名,用于續(xù)幀調(diào)試器中顯示緩沖區(qū)名稱
        const string CommandBufferTag = "AdditionalPostProcessing Pass";
    
        // 用于后處理的材質(zhì)
        public Material m_Material;

        // 屬性參數(shù)組件
        BrightnessSaturationContrast m_BrightnessSaturationContrast;

        // 顏色渲染標識符
        RenderTargetIdentifier m_ColorAttachment;
        // 臨時的渲染目標
        RenderTargetHandle m_TemporaryColorTexture01;

        public AdditionPostProcessPass()
        {          
            m_TemporaryColorTexture01.Init("_TemporaryColorTexture1");
        }

        // 設置渲染參數(shù)
        public void Setup(RenderTargetIdentifier _ColorAttachment, Material Material)
        {
            this.m_ColorAttachment = _ColorAttachment;

            m_Material = Material;
        }     

        /// <summary>
        /// URP會自動調(diào)用該執(zhí)行方法
        /// </summary>
        /// <param name="context"></param>
        /// <param name="renderingData"></param>
        public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
        {
            // 從Volume框架中獲取所有堆棧
            var stack = VolumeManager.instance.stack;
            // 從堆棧中查找對應的屬性參數(shù)組件
            m_BrightnessSaturationContrast = stack.GetComponent<BrightnessSaturationContrast>();

            // 從命令緩沖區(qū)池中獲取一個帶標簽的渲染命令,該標簽名可以在后續(xù)幀調(diào)試器中見到
            var cmd = CommandBufferPool.Get(CommandBufferTag);

            // 調(diào)用渲染函數(shù)
            Render(cmd, ref renderingData);

            // 執(zhí)行命令緩沖區(qū)
            context.ExecuteCommandBuffer(cmd);
            // 釋放命令緩存
            CommandBufferPool.Release(cmd);
            // 釋放臨時RT
            cmd.ReleaseTemporaryRT(m_TemporaryColorTexture01.id);
        }

        // 渲染
        void Render(CommandBuffer cmd, ref RenderingData renderingData)
        {       
            // VolumeComponent是否開啟,且非Scene視圖攝像機
            if (m_BrightnessSaturationContrast.IsActive() && !renderingData.cameraData.isSceneViewCamera)
            {
                // 寫入?yún)?shù)
                m_Material.SetFloat("_Brightness", m_BrightnessSaturationContrast.brightness.value);
                m_Material.SetFloat("_Saturation", m_BrightnessSaturationContrast.saturation.value);
                m_Material.SetFloat("_Contrast", m_BrightnessSaturationContrast.contrast.value);

                // 獲取目標相機的描述信息
                RenderTextureDescriptor opaqueDesc = renderingData.cameraData.cameraTargetDescriptor;
                // 設置深度緩沖區(qū)
                opaqueDesc.depthBufferBits = 0;
                // 通過目標相機的渲染信息創(chuàng)建臨時緩沖區(qū)
                cmd.GetTemporaryRT(m_TemporaryColorTexture01.id, opaqueDesc);

                // 通過材質(zhì),將計算結(jié)果存入臨時緩沖區(qū)
                cmd.Blit(m_ColorAttachment, m_TemporaryColorTexture01.Identifier(), m_Material);
                // 再從臨時緩沖區(qū)存入主紋理
                cmd.Blit(m_TemporaryColorTexture01.Identifier(), m_ColorAttachment);
            }
        }       
    }
}

AdditionPostProcessRendererFeature

namespace UnityEngine.Rendering.Universal
{
    /// <summary>
    /// 可編程渲染功能
    /// 必須要繼承ScriptableRendererFeature抽象類,
    /// 并且實現(xiàn)AddRenderPasses跟Create函數(shù)
    /// </summary>
    public class AdditionPostProcessRendererFeature : ScriptableRendererFeature
    {
        // 用于后處理的Shader 
        public Shader shader;
        // 后處理Pass
        AdditionPostProcessPass postPass;
        // 根據(jù)Shader生成的材質(zhì)
        Material _Material=null;

        //在這里,您可以在渲染器中注入一個或多個渲染通道。
        //每個攝像機設置一次渲染器時,將調(diào)用此方法。
        public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
        {
            // 檢測Shader是否存在
            if (shader == null)
                return;

            // 創(chuàng)建材質(zhì)
            if (_Material==null)
                _Material = CoreUtils.CreateEngineMaterial(shader);

            // 獲取當前渲染相機的目標顏色,也就是主紋理
            var cameraColorTarget = renderer.cameraColorTarget;     

            // 設置調(diào)用后處理Pass
            postPass.Setup(cameraColorTarget, _Material);
            
            // 添加該Pass到渲染管線中
            renderer.EnqueuePass(postPass);
        }

       
        // 對象初始化時會調(diào)用該函數(shù)
        public override void Create()
        {
            postPass = new AdditionPostProcessPass();
            // 渲染時機 = 透明物體渲染后
            postPass.renderPassEvent = RenderPassEvent.AfterRenderingTransparents; 
        }
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容