螢幕後效果指的是,目前整個場景圖已經渲染完成輸出到螢幕後,再對輸出的螢幕圖像進行的操作。
在Unity中,一般過程通常是:
1.建立用于處理效果的shader和臨時材質,給shader腳本傳遞需要控制的參數和變量
2.利用OnRenderImage函數抓取目前螢幕渲染紋理
OnRenderImage(RenderTexture source, RenderTexture destination){ }
第一個參數為處理前紋理,第二個為最終顯示紋理
3.在OnRenderImage函數中調用Graphics.Blit方法對抓取的紋理進行具體的後期操作
Graphics.Blit(source, destination, material,-1);
material為需要處理的材質,-1為參數pass的預設值,表示對shader中所有的pass依次調用,這裡也可以省略
為此,首先可以提前建立一個基類ScreenEffectBase,主要用于檢查Shader并建立臨時材質:
腳本如下:
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 }
效果如下(随便調的不用在意~):
