能夠確定的說Unity3D使得不少開發者開發遊戲更容易。毫無疑問,shader(着色器)編碼,仍有很長的路要走。shader是一個專門運行在GPU的程序,常常被神祕包圍,它最終繪製3D模型的三角形。若是你想給遊戲一個特殊的顯示,學習如何編寫shader是必要的。Unity3D使用shader作後期處理,對2D遊戲也是必不可少的。這個系列的文章將逐步介紹shader編程,並面向幾乎沒有任何shader知識的開發者。
下圖大體表示了在Unity3D渲染流程中發揮做用的3個不一樣實體:
3D模型本質上是,被稱爲頂點的3D座標集合。他們鏈接在一塊兒構成一些三角形。每一個頂點包含一些其它的信息,如顏色、點指的方向(法線)、紋理映射座標(UV數據)。
沒有材質模型是不能被渲染的。材質包含一個shader和其屬性值的封裝。所以,不一樣材質能夠共享相同的shader,賦予不一樣的數據。
Unity3D支持兩種不一樣的shader:表面shader、片斷和頂點shader。還有第三種類型:固定管線shader,可是現在已通過時了,將不包含在本系列文章。不管你須要的是哪一種類型,shader的結構都同樣:
Shader "MyShader"
{
Properties
{
// The properties of your shaders
// - textures
// - colours
// - parameters
// ...
}
SubShader
{
// The code of your shaders
// - surface shader
// OR
// - vertex and fragment shader
// OR
// - fixed function shader
}
}
|
能夠包含多個SubShader,一個接一個。他們包含GPU的實際指令。Unity3D將找到與你顯卡兼容的SubShader,並順序執行他們。這對多平臺編碼是很是有用,由於你能夠在一個文件中編寫同一shader的不一樣版本。
shader的屬性在某種程度上至關於C#腳本中的public字段,他們將出如今材質的inspector面板,給你機會來調整。但不像腳本,材質是資源:編輯中游戲運行時修改材質的屬性值是永久的。甚至遊戲中止後,修改的屬性值也是有效的。
下面的代碼片斷涵蓋了你能夠在shader中使用的全部基本類型的定義:
3~4行中的2D,表示參數是紋理。他們能夠初始化爲white、black、gray。你也可使用bump表示使用法線貼圖,這種狀況下,它將自動初始爲顏色#808080,這用來表示沒有任何凸凹。Vector和Color老是有4個元素(分別爲xyzw和rgba)。
下圖展現了一個shader附着到一個材質上以後,在inspector面板中是如何顯示的。
不幸的是,這對咱們使用屬性還不夠。事實上,Properties塊被Unity3D用來從inspector訪問shader隱藏變量。這些變量仍需定義在shader中,它們包含在SubShader塊中。
紋理的類型爲sampler2D。向量是float4、顏色通常是half4,分別使用32和16位表示。用來編寫shader的語言爲Cg/HLSL,很迂腐:參數的名稱必須與先前定義的匹配。然而類型不須要,例如把_MyRange聲明爲half而不是float不會報任何錯誤。一些使人困惑的是,若是你定一個向量類型的屬性,關聯到一個float2變量,額外的2個值將被Unity3D忽略。
正如已提到的,SubShader塊包含實際代碼,使用Cg/HLSL(很是像C)編寫。不嚴格地說,一個shader爲圖像的每一個像素執行,它的性能很是關鍵。因爲GPU的體系結構,一個shader中可以執行的指令數量有限制。能夠經過分割幾個部分執行,但本教程不包含這塊。
一個SubShader一般看起來像這樣:
第8~11行包含實際的Cg代碼,經過CGPROGRAM和ENDCG指令示意。
第3行,在實際代碼以前,介紹tags的概念。tags用來告訴Unity3D咱們寫的shader的某些屬性。例如,shader渲染的順序(Queue)和應該如何渲染(RenderType)。
當渲染三角形時,GPU一般根據它們離攝像機的距離,遠的先繪製。這在渲染不透明的幾何形狀時夠用了,可是透明物體將失敗。這也是爲何Unity3D運行指定Queue標籤,能夠控制每一個材質的渲染順序。Queue接受正整數(越小越先繪製),預約義(mnemonic)的標籤也可使用:
l Background(1000):用於背景和天空盒
l Geometry(2000):默認標籤,用於大部分不透明物體
l Transparent(3000):用於包含透明屬性的材質,例如玻璃、火、粒子、水
l Overlay(4000):用於鏡頭耀斑,GUI元素和文本
Unity3D還容許指定相關順序,例如Background+2,表示1002隊列值。搞亂了Queue值會致使惡劣的狀況,一個對象老是被繪製,即便它應該被其餘模型遮擋住了。
記住,一個包含透明屬性(Transparent)的對象並不老是顯示在不透明(Geometry)對象上面。默認狀況下,GPU執行ZTest避免隱藏的對象被繪製。原理是,它使用了一個額外的緩衝區,其大小與屏幕渲染的相同。每一個像素包含繪製對象在該像素的深度(離相機的距離)。若是咱們要繪製一個像素比當前深度更大,像素就被丟棄。ZTest剪裁被其它對象遮擋住的像素,不管他們繪製到屏幕上的順序。
shader代碼的最後一部分。在渲染以前,須要決定使用那種類型的shader。本節將給出shader效果驚鴻一瞥的樣子,但不會深刻解釋。表面、頂點和片斷shader將在本教材的下一部分覆蓋。
當材質須要根據光照模擬實際效果時,那麼你就須要一個表面shader。表面shader在函數surf中隱藏光線如何被反射的計算,並容許指定「直觀」的屬性,如反照率、法線、反射率等。而後將這些值插入到光照模型,將輸出每一個像素的最終RGB值。或者,當須要很是高級的效果是,你也能夠編寫本身的光照模型。
一個典型的表面shader的Cg代碼以下所示:
第5行指定輸入的紋理,而後在第12行將指定Albedo屬性。第3行指定使用Lambertian光照模型,這個是很是典型光照如何影響對象的模型。shader僅使用反照率屬性一般稱爲漫反射(diffuse)。
頂點和片斷shader的工做貼近GPU渲染三角形的方式,並無光照如何表現的概念。模型的幾何形狀首先經過一個調用函數vert,改變他的頂點。而後各個三角形經過另外一個調用函數frag,這決定了最終每一個像素的RGB顏色。這對2D效果很是有用,後期處理和特殊的3D效果很是付出須要使用表面shader。
下面的頂點和片斷shader簡單只是使用紅色,沒有光照:
第15~17行,將原始的3D空間頂點轉換到最終的2D屏幕位置。Unity3D使用UNITY_MATRIX_MVP實現,隱藏了底層的實現數學運算。在此以後,第22行,給定每一個像素爲紅色。只須要記住,頂點和片斷shader的Cg部分須要封裝到Pass塊中。它跟簡單的表面shader不同。
本篇文章逐漸引入了兩種類型的Unity3D shader,並說明什麼時候須要使用。接下來四篇文章,將介紹實現它們的細節。還有一個附加篇,將介紹屏幕shader,用於2D圖像的後期處理。