基於 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 轉換為頂點和片段著色器

編寫一個著色器的準備工作

  1. 3D 計算機圖形學的基礎知識,需要理解完整的 3D 圖形學流水線。包括模型變換、 顏色、 紋理、 光照、 陰影、 渲染路徑等等知識,才能夠深入理解著色器的本質。
  2. 學習 GLSL、 Cg 或者 HLSL 中的一門著色器語言用於編寫著色器代碼

HLSL: msdn.microsoft.com/en-u

GLSL: opengl.org/documentatio

Cg: developer.nvidia.com/cg

實現殭屍狂暴效果

  • 創建自定義著色器 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 系列活動現場彙報(上)
技術宅救世界:英國遊戲行業的啟蒙往事

TAG:shader | 计算机图形学 | 游戏开发 |