基於 Unity 引擎的遊戲開發進階之 著色器(Shader)入門 & 圖形特效
著色器的定義
著色器本質上是一種運行在顯卡 CPU 上的程序,用於控制顯卡的圖形渲染過程。CPU 運行的程序通常用彙編語言,或者 C++、Java 等高級語言編寫。GPU 採用的是不同於 CPU 的並行計算結構,需要一種適用於 GPU 的編程語言,於是就有了著色器語言。
著色器語言
HLSL(基於 Direct3D 圖形庫), GLSL(基於 OpenGL 圖形庫), Cg(NVidia 與微軟合作研發)
在 Unity 中,所有的渲染都需要通過 Shader 來完成。Unity 內建超過 80 種著色器,開發人員可以使用內建著色器實現各種畫面效果,還可以方便的對其進行擴展。同時,Unity 也允許開發者編寫自己的 Shader。Unity 使用自定義 ShaderLab 開發語言來組織著色器,針對不同平台進行編譯。
材質和著色器
材質定義了物體表面的顯示效果,每個材質必須綁定一個著色器。材質綁定的著色器決定了該材質的渲染方式,以及可配置屬性的類型和數量。
新建一個材質後,我們首先要做的就是為這個材質添加一個著色器。具體的做法是選中材質,在 Inspector 視圖的 Shader 下拉列表中選擇著色器。指定好著色器後,需要配置材質的各個屬性,並在檢視圖下方預覽材質效果。
Unity 內建著色器
- 為了方便開發者,Unity 提供了超過 80 種內建著色器,能夠實現從簡單的頂點光照,到高光,透明,反射等遊戲中常用的材質效果。
- 可以在材質的檢視視圖中找到並使用這些著色器
- 內建著色器按功能分類存放
Unity 內置著色器分類
- Standard 和 Standard(Specular setup):標準著色器
- FX:光照,水於玻璃效果著色器
- GUI 和 UI :用戶界面著色器
- Mobile:移動平台使用的簡單著色器
- Nature:植被和地形著色器
- Particles:粒子系統使用的著色器
- SkyBox:天空盒等背景環境著色器
- Sprites:2D 精靈系統著色器
- Unlit:忽略一切光照和陰影效果的著色器
- Legacy:過時著色器
Unity5.0 新加入的標準著色器 StandardShader,有選擇的吸收了許多其他不同著色器的特色功能,能滿足大部分的著色器需求,並顯著的簡化工作流程。
標準著色器的可配置屬性雖然種類繁多,但只有設置過的屬性對應的功能才會被開啟,其他未設置屬性對應的功能則保持禁用狀態,因此可以根據具體需求,使用和設置著色器的屬性,不用擔心著色器的性能。
考慮到手機移動設備計算能力有限,Unity 為移動設備提供了一組經過特殊優化的內建著色器。
- UnLit:忽略光照和陰影的著色器
- VertexLit:頂點光照著色器
- Diffuse:漫反射效果
- Bumped Diffuse:帶法向貼圖的漫反射著色器
- Bumped Specular:帶法向貼圖和鏡面反射效果的漫反射著色器
這些著色器按照計算開銷,從低到高排序,相應地,排列靠後的著色器達到的效果也更好,開發者在使用著色器時,需要在遊戲畫面品質和遊戲性能之間做出權衡,選擇合適的著色器。
Unlit 著色器速度最快,但沒有任何光照和陰影效果,無法在地面上產生陰影,也無法接受其他物體產生的陰影。Vertex Light 頂點光照著色器,它的速度較快,可以產生陰影,但是不會接受陰影。Diffuse 著色器用於計算漫反射效果,具有光照效果。能夠產生陰影,也可以接受陰影。Bumped Diffuse 是帶法向貼圖的漫反射著色器,運用法向貼圖可以在表面看到凸凹的效果。Bumped specular 是帶法向貼圖的高光效果的漫反射著色器,具有高光效果。
Unity 自定義著色器
創建著色器腳本
ShaderLab 著色器腳本結構
Shader "Custom/MyShader"{ Properties{ //Properties 是著色器的屬性,可能是紋理,顏色或者其他參數 } SubShader{ //SubShader 中包含了一個具體的著色器 } SubShader{ //後一個 SubShader 是前一個 SubShader 的簡單版 //當顯卡不支持前一個 SubShader 時,會嘗試後一個 Shader } FallBack "Diffuse" //顯卡不支持前面所有 SubShader 時的選擇}
ShaderLab 支持的著色器類型
- 固定功能管線著色器 Fixed Function Shaders
- 頂點和片段著色器 Vertex and fragment shader
- 表面著色器 Surface shader
固定功能管線著色器
- 用於不支持高級著色器特性的舊硬體
- 完全使用 ShaderLab 語言編寫
頂點和片段著色器
- 頂點和片段著色器功能強大,但複雜難寫。它是 GPU 的編程語言,目前有三種語言可供選擇,分別是基於 Direct3D 圖形庫的 HLSL、基於 OpenGL 的 GLSL、NIVIDIA 與微軟合作開發的 Cg
- Unity ShaderLab 支持以上三種語言
表面著色器
- 表面著色器是 ShaderLab 語言所特有,能使開發者以相對簡便的方式實現複雜的功能
- 關鍵代碼使用 Cg/HLSL 語言編寫,嵌入到 ShaderLab 的 SubShader 代碼塊
- Surface Shader 最終被 Unity 轉換為頂點和片段著色器
編寫一個著色器的準備工作
- 3D 計算機圖形學的基礎知識,需要理解完整的 3D 圖形學流水線。包括模型變換、 顏色、 紋理、 光照、 陰影、 渲染路徑等等知識,才能夠深入理解著色器的本質。
- 學習 GLSL、 Cg 或者 HLSL 中的一門著色器語言用於編寫著色器代碼
HLSL: https://msdn.microsoft.com/en-us/library/bb509561(VS.85).aspx
GLSL: https://www.opengl.org/documentation/glsl/
Cg: https://developer.nvidia.com/cg-toolkit
實現殭屍狂暴效果
- 創建自定義著色器 body_shader,填入邊緣泛光效果的著色器代碼
Shader "Custom/body_shader" { //表示該著色器的名字,位於材質下拉列表的 Custom 子列表 Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} _Glossiness ("Smoothness", Range(0,1)) = 0.5 _Metallic ("Metallic", Range(0,1)) = 0.0 _BumpMap ("Bumpmap", 2D) = "bump" {} _RimColor ("Rim Color", Color) = (0.26,0.19,0.16,0.0) _RimPower ("Rim Power", Range(0.5,8.0)) = 3.0 _RimBool ("EnableRim", Range(0.0,1.0)) = 0.0 } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM // Physically based Standard lighting model, and enable shadows on all light types #pragma surface surf Standard fullforwardshadows // Use shader model 3.0 target, to get nicer looking lighting #pragma target 3.0 sampler2D _MainTex; struct Input { float2 uv_MainTex; float2 uv_BumpMap; float3 viewDir; }; half _Glossiness; half _Metallic; fixed4 _Color; sampler2D _BumpMap; float4 _RimColor; float _RimPower; float _RimBool; void surf (Input IN, inout SurfaceOutputStandard o) { // Albedo comes from a texture tinted by color fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; o.Albedo = c.rgb; // Metallic and smoothness come from slider variables o.Metallic = _Metallic; o.Smoothness = _Glossiness; o.Alpha = c.a; o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap)); if(_RimBool >0.5) { half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal)); o.Emission = _RimColor.rgb * pow (rim, _RimPower); }else{ o.Emission = float4(0,0,0,1); } } ENDCG } FallBack "Diffuse"}
- 使用 body_shader 著色器,創建具有狂暴效果的殭屍材質 body_rim ,並把它應用到殭屍對象的皮膚渲染器
- 為殭屍綁定 ZombieRender.cs 腳本,控制狂暴狀態的開啟和關閉
public class ZombieRender : MonoBehaviour { private Renderer[] rends; //殭屍皮膚渲染器數組 private int rendCnt = 0; //殭屍皮膚渲染器數組計數器 void Start() { //獲取殭屍身體各部分的皮膚渲染器 rends = GetComponentsInChildren<SkinnedMeshRenderer>(); //獲取皮膚渲染器的個數 rendCnt = rends.Length; } //進入狂暴模式 public void SetCrazy() { //把殭屍皮膚渲染器材質屬性EnableRim,在著色器中名為_RimBool,設置為1.0開啟狂暴效果。 for(int i=0;i<rendCnt;i++) rends [i].material.SetFloat ("_RimBool", 1.0f); } //進入正常(非狂暴)模式 public void SetNormal() { //把殭屍皮膚渲染器材質屬性EnableRim,在著色器中名為_RimBool,設置為0.0關閉狂暴效果。 for(int i=0;i<rendCnt;i++) rends [i].material.SetFloat ("_RimBool", 0.0f); }}
- 修改殭屍 AI 腳本,是殭屍只在搜索,追蹤和攻擊狀態下呈現出周身泛出血紅色光芒的效果
//進入狂暴狀態if(zombieRender!=null)zombieRender.SetCrazy();
//進入普通狀態if(zombieRender!=null)zombieRender.SetNormal();
附加
Unity著色器:
固定功能管線著色器的Unity官方教程
頂點和片段著色器的Unity官方教程
表面著色器的Unity官方教程
著色器編程語言:
HLSL著色器語言官方網站
GLSL著色器語言官方網站
Cg著色器語言官方網站
圖像特效 Image Effect
Image Effect 圖像特效技術,對遊戲渲染出的畫面進行後期處理,可以為遊戲帶來豐富的視覺效果。
圖像特效資源
圖像特效資源通常是一個腳本文件,該腳本包含一個繼承了 MonoBehaviour 的類,實現了 OnRenderImage 函數。
public class ExampleClass : MonoBehaviour{ public Material mat; void OnRenderImage(RenderTexture src, RenderTexture dest){ Graphics.Blit(src, dest, mat); }}
OnRenderImage 函數的 src 參數用於接收遊戲渲染出的原始畫面,dest 參數用於返回特效處理後的結果畫面。
圖像特效分類介紹
- Bloom and Glow:泛光特效
- Blur:模糊特效
- Camera:相機特效
- Color Adjustments:顏色調整特效
- Edge Detection:邊緣檢測特效
- Displacement:位移特效
- Rendering:渲染特效
- Noise:噪點特效
- Other:其他特效
在 Unity 中的應用
1.導入資源
2.在玩家的的攝像機上添加特效
3.設置屬性
4.最後預覽遊戲,觀察結果
推薦閱讀:
※《InsideUE4》GamePlay架構(四)Pawn
※遊戲里如何實現 "敵人發現了你"?
※遊必有方 Vol.10 NYU Practice 系列活動現場彙報(上)
※技術宅救世界:英國遊戲行業的啟蒙往事