屏幕後效果指的是,當前整個場景圖已經渲染完成輸出到屏幕後,再對輸出的屏幕圖像進行的操做。app
在Unity中,通常過程一般是:ide
1.創建用於處理效果的shader和臨時材質,給shader腳本傳遞須要控制的參數和變量函數
2.利用OnRenderImage函數抓取當前屏幕渲染紋理測試
OnRenderImage(RenderTexture source, RenderTexture destination){ }ui
第一個參數爲處理前紋理,第二個爲最終顯示紋理spa
3.在OnRenderImage函數中調用Graphics.Blit方法對抓取的紋理進行具體的後期操做code
Graphics.Blit(source, destination, material,-1);blog
material爲須要處理的材質,-1爲參數pass的默認值,表示對shader中全部的pass依次調用,這裏也能夠省略繼承
爲此,首先能夠提早創建一個基類ScreenEffectBase,主要用於檢查Shader並建立臨時材質:ip
腳本以下:
1 using UnityEngine; 2 3 [ExecuteInEditMode] 4 //屏幕後處理效果主要是針對攝像機進行操做,須要綁定攝像機 5 [RequireComponent(typeof(Camera))] 6 public class ScreenEffectBase : MonoBehaviour 7 { 8 public Shader shader; 9 private Material material; 10 protected Material Material 11 { 12 get 13 { 14 material = CheckShaderAndCreatMat(shader, material); 15 return material; 16 } 17 } 18 19 //用於檢查並建立臨時材質 20 private Material CheckShaderAndCreatMat(Shader shader, Material material) 21 { 22 Material nullMat = null; 23 if (shader != null) 24 { 25 if (shader.isSupported) 26 { 27 if (material && material.shader == shader){ } 28 else 29 { 30 material = new Material(shader){ hideFlags = HideFlags.DontSave }; 31 } 32 return material; 33 } 34 } 35 return nullMat; 36 } 37 }
以後建立的屏幕後處理效果的控制腳本均可以繼承自該基類,例如咱們建立關於基本顏色校訂的控制腳本:
1 using UnityEngine; 2 3 public class ColorCorrectionCtrl : ScreenEffectBase 4 { 5 private const string _Brightness = "_Brightness"; 6 private const string _Saturation = "_Saturation"; 7 private const string _Contrast = "_Contrast"; 8 9 [Range(0, 3)] 10 public float brightness = 1.0f; 11 [Range(0, 3)] 12 public float saturation = 1.0f; 13 [Range(0, 3)] 14 public float contrast = 1.0f; 15 16 private void OnRenderImage(RenderTexture source, RenderTexture destination) 17 { 18 if (Material!=null) 19 { 20 Material.SetFloat(_Brightness, brightness); 21 Material.SetFloat(_Saturation, saturation); 22 Material.SetFloat(_Contrast, contrast); 23 24 Graphics.Blit(source, destination, Material); 25 } 26 else 27 Graphics.Blit(source, destination); 28 } 29 }
其中,brightness,saturation,contrast分別爲調整參數——亮度,飽和度和對比度,_Brightness,_Saturation,_Contrast爲以後對應的shader中須要相應定義的屬性參數。
這裏利用構建的材質Material對shader的屬性賦值並調用Graphics.Blit進行屏幕後效果的處理。
具體實現顏色校訂的shader以下:
1 Shader "MyUnlit/ColorCorrection" 2 { 3 Properties 4 { 5 //這裏的參數主要用於展現在材質面板中進行調節,但由於此次是臨時建立的材質,參數都已經放在了C#腳本中調整,所以相對應的參數均可以省略 6 _MainTex ("Texture", 2D) = "white" {} 7 } 8 SubShader 9 { 10 Tags { "RenderType"="Opaque" } 11 12 Pass 13 { 14 //OnRenderImage的調用可能會發生在渲染透明物體以前,爲了避免影響以後透明物體的渲染,須要:開啓深度測試+雙面渲染+關閉深度寫入 15 ZTest always 16 Cull off 17 ZWrite off 18 19 CGPROGRAM 20 #pragma vertex vert 21 #pragma fragment frag 22 #pragma multi_compile_fog 23 24 #include "UnityCG.cginc" 25 26 struct appdata 27 { 28 float4 vertex : POSITION; 29 float2 uv : TEXCOORD0; 30 }; 31 32 struct v2f 33 { 34 float2 uv : TEXCOORD0; 35 UNITY_FOG_COORDS(1) 36 float4 vertex : SV_POSITION; 37 }; 38 39 sampler2D _MainTex; 40 half _Brightness; 41 half _Saturation; 42 half _Contrast; 43 44 v2f vert (appdata v) 45 { 46 v2f o; 47 o.vertex = UnityObjectToClipPos(v.vertex); 48 //由於是臨時建立的材質,這裏不須要對紋理進行任何變換操做(無可操做的材質面板),直接傳遞便可,_MainTex_ST也不須要定義 49 o.uv = v.uv; 50 UNITY_TRANSFER_FOG(o,o.vertex); 51 return o; 52 } 53 54 fixed4 frag (v2f i) : SV_Target 55 { 56 fixed4 col = tex2D(_MainTex, i.uv); 57 58 //亮度計算直接疊加 59 fixed3 color = col.rgb*_Brightness; 60 61 //飽和度和灰度有關,先計算最低灰度係數下的圖像,隨後對原始的圖像進行插值操做 62 fixed3 gray = fixed3(0.2125, 0.7154, 0.0721); 63 //點積獲得最低灰度值,構成最低灰度圖像 64 fixed minGray = dot(gray, col.rgb); 65 fixed3 grayColor = fixed3(minGray, minGray, minGray); 66 //對灰度圖像和原始圖像插值操做以獲得最終係數的顯示圖像 67 color = lerp(grayColor, color, _Saturation); 68 69 //對比度效果相似,先計算最低對比度圖像,即(0.5,0.5,0.5),隨後插值操做 70 fixed3 minContrast = fixed3(0.5, 0.5, 0.5); 71 color = lerp(minContrast, color, _Contrast); 72 73 //獲得全部處理完成後的圖像顏色,但alpha保持不變 74 fixed4 finColor = fixed4(color, col.a); 75 76 UNITY_APPLY_FOG(i.fogCoord, finColor); 77 return finColor; 78 } 79 ENDCG 80 } 81 } 82 //關閉回調 83 fallback off 84 }
效果以下(隨便調的不用在乎~):