URP屏幕后處理
由于Unity對URP的屏幕后處理需集成要到2019.4版本后才穩(wěn)定,所以升級Unity版本到2019.4.9
Post Processing
在創(chuàng)建我們自己屏幕后處理系統(tǒng)前,我們需要先學會使用UnityURP管線中集成的屏后處理系統(tǒng)。
低于Unity2019.4版本的URP是沒有Volume組件的
-
我們可以將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ū)域
-
在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ù) -
點擊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
-
當我們?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)AddRenderPasses跟Create函數(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ù)腳本
編寫類BrightnessSaturationContrast繼承VolumeComponent組件和IPostProcessComponent接口,用以繼承Volume框架。
-
在方法中我們根據(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腳本
創(chuàng)建C#腳本AdditionPostProcessPass,繼承自ScriptableRenderPass,并實現(xiàn)Execute方法。
-
創(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; -
創(chuàng)一個入口函數(shù),用于后續(xù)渲染管線功能腳本寫入?yún)?shù)
// 設置渲染參數(shù) public void Setup(RenderTargetIdentifier _ColorAttachment, Material Material) { this.m_ColorAttachment = _ColorAttachment; m_Material = Material; } -
修改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); } -
接下來我們編寫渲染方法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)建可編程渲染功能腳本
創(chuàng)建類AdditionPostProcessRendererFeature,繼承ScriptableRendererFeature抽象類,并實現(xiàn)AddRenderPasses跟Create方法
-
設置三個參數(shù),公開屬性Shader、私有屬性AdditionPostProcessPass對象和材質(zhì)
// 用于后處理的Shader public Shader shader; // 后處理Pass AdditionPostProcessPass postPass; // 根據(jù)Shader生成的材質(zhì) Material _Material=null; 修改Create方法,在方法中創(chuàng)建AdditionPostProcessPass對象,并修改該類的渲染時機,在透明物體渲染后。
-
修改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); }
配置管線
-
配置Volume組件,將BrightnessSaturationContrast屬性參數(shù)組件添加到效果列表中
-
配置管線,在URP管線的配置文件中添加我們編寫的渲染功能AdditionPostProcessRendererFeature
-
賦值Shader
-
修改屬性參數(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;
}
}
}









