如U3D中Hierarchy面板下的搜索效果:
講解分析:
1.這種PostEffect效果其實就是指Unity shader的后處理,即游戲中實現屏幕特效的常見方法。顧名思義屏幕后處理就是指在渲染完整個場景得到屏幕圖像后,再對這個圖像進行一系列操作,實現各種屏幕特效。
2.要實現這種屏幕后處理的基礎在於得到渲染后的屏幕圖像,即抓取屏幕,Unity中提供給我們一個方便接口——OnRenderImage函數。
3.OnRenderImage函數定義為MonoBehaviour.OnRenderImage (RenderTexture src, RenderTexture dest); Unity會把當前渲染得到的圖像存儲在第一個參數對應的源渲染紋理中,通過該函數一系列操作后,再把目標渲染紋理,即第二個參數對應的渲染紋理顯示到屏幕上。在OnRenderImage函數中,通常利用Graphics.Blit函數來完成對渲染紋理的處理。(若dest為null,就會直接將結果顯示到屏幕上)。
src紋理是源紋理,在屏幕后處理技術中,該參數就是當前屏幕的渲染紋理或者是上一步處理后得到的渲染紋理。參數mat是材質,此材質使用的Unity Shader將會進行各種屏幕后處理操作,而src紋理將會被傳遞給材質的shader中名為_MainTex的紋理屬性。參數pass的默認值為-1,即依次執行shader中的所有Pass,否則 僅會調用給定索引的Pass。
4.整個過程如下:
首先在攝像機中添加一個用於屏幕后處理的腳本。在該腳本中,我們會實現OnRenderImage函數來獲取當前屏幕的渲染紋理。其次,再調用Graphics.Blit函數使用特定的Unity Shader來對當前圖像進行處理,再把返回的渲染紋理顯示到屏幕上。對於一些復雜的屏幕特效,可能多次調用Graphics.Blit函數對上一步輸出結果進行下一步處理。
詳細代碼:
PostEffect.cs
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 using UnityEngine.Rendering; 5 6 7 [ExecuteInEditMode] 8 public class PostEffect : MonoBehaviour 9 { 10 11 #region Variables 12 public float grayScaleAmout = 1.0f; 13 14 //主相機 15 public Camera sourceCamera; 16 17 //操作相機(為了結合另一個PostEffect,(OutlineEffect操作的相機)) 18 public Camera outlineCamera; 19 20 //渲染紋理 21 RenderTexture renderTexture; 22 23 //開始灰色渲染效果標志 24 public bool isStart = false; 25 26 //材質 27 Material material = null; 28 29 #endregion 30 31 void Start() 32 { 33 if (material == null) 34 { 35 material = new Material(Resources.Load<Shader>("NewUnlitShader")); 36 } 37 } 38 39 void OnPreRender() 40 { 41 if (renderTexture == null || renderTexture.width != sourceCamera.pixelWidth || renderTexture.height != sourceCamera.pixelHeight) 42 { 43 renderTexture = new RenderTexture(sourceCamera.pixelWidth, sourceCamera.pixelHeight, 16, RenderTextureFormat.Default); 44 outlineCamera.targetTexture = renderTexture; 45 } 46 outlineCamera.Render(); 47 } 48 49 void OnRenderImage(RenderTexture source, RenderTexture target) 50 { 51 if (isStart) 52 { 53 if (material != null) 54 { 55 material.SetTexture("_OutLine", outlineCamera.targetTexture); 56 material.SetFloat("_LuminosityAmount", grayScaleAmout); 57 Graphics.Blit(source, target, material); 58 } 59 } 60 else 61 { 62 Graphics.Blit(source, target); 63 } 64 } 65 66 void OnDisable() 67 { 68 if (material) 69 { 70 DestroyImmediate(material); 71 } 72 } 73 }
shader部分:
Shader "Custom/GrayScale" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} _LuminosityAmount ("GrayScale Amount", Range(0.0, 1)) = 1.0 } SubShader { Pass { CGPROGRAM #pragma vertex vert_img #pragma fragment frag #pragma fragmentoption ARB_precision_hint_fastest #include "UnityCG.cginc" uniform sampler2D _MainTex; fixed _LuminosityAmount; uniform sampler2D _OutLine; fixed _NumPixelH; fixed _NumPixelV; fixed4 frag(v2f_img i) : COLOR { fixed4 outlineTex = tex2D(_OutLine, i.uv); fixed4 renderTex = tex2D(_MainTex, i.uv); if((outlineTex.r+outlineTex.b+outlineTex.g+outlineTex.a)<0.1f) { float luminosity = 0.299 * renderTex.r + 0.587 * renderTex.g + 0.114 * renderTex.b; fixed4 finalColor = lerp(renderTex, luminosity, _LuminosityAmount); return finalColor; } else { return renderTex; } } ENDCG } } FallBack "Diffuse" }
注釋:
判斷紋理頂點色值,我的源紋理初始色為黑色,所以搜索的物體附上色值,判斷rgba的和是否為0,0為黑色,1為白色,黑色部分置灰(沒選中的物體及場景其他部分),有色差的部分為選中部分返回當前color。
這效果結合上一篇的Outline效果,源紋理為上一篇處理的紋理,即_OutLine ,_MainTex為主紋理,即當前屏幕紋理。
測試代碼:

1 using cakeslice; 2 using System.Collections; 3 using System.Collections.Generic; 4 using System.Text; 5 using UnityEngine; 6 using UnityEngine.UI; 7 8 public class test : MonoBehaviour 9 { 10 public InputField Txt; 11 12 GameObject go = null; 13 14 public void OnClick() 15 { 16 var chr = Txt.text.ToCharArray(); 17 StringBuilder stringBuilder = new StringBuilder(); 18 for (int i = 0; i < chr.Length; i++) 19 { 20 if (i == 0) 21 { 22 stringBuilder.Append(chr[0].ToString().ToUpper()); 23 } 24 else 25 { 26 stringBuilder.Append(chr[i].ToString().ToLower()); 27 } 28 } 29 Debug.Log(stringBuilder.ToString()); 30 31 go = GameObject.Find(stringBuilder.ToString()); 32 if (go != null) 33 { 34 go.GetComponent<cakeslice.Outline>().Add(); 35 Camera.main.GetComponent<PostEffect>().isStart = true; 36 } 37 else 38 { 39 Debug.Log("根據 "+ Txt.text + " 未找到搜索物體,請查看是否輸入錯誤"); 40 } 41 } 42 43 public void UnDo() 44 { 45 if (go!=null) 46 { 47 go.GetComponent<cakeslice.Outline>().Remove(); 48 Camera.main.GetComponent<PostEffect>().isStart = false; 49 go = null; 50 } 51 } 52 }