Unity

Unity

官方網站:點擊進入
官方粉絲團:點擊進入

《Unity》Shader 02: CG的基礎結構

【Unity】 【3D】 【CG】 【Shader】 【結構】 【渲染】
作者:Hui-Ku Shih 時間:2015-10-13

原文:Unity3D Shader 02: CG的基礎結構~

  在開始之前,感謝大家熱情迴響。我會盡力的在周末不工作的晚上寫這個..... 所以大概速度是一周一到兩集,端看該集內容而定。

廢話不多說,我們開始CG的基礎架構。

 

還記得我們上一集最後面給大家一張簡單的CG shader 所表示得shader lab 的架構圖,重申所謂的CG只出現在兩個旗標中間

 

CGPROGRAM

............ 

ENDCG

 

而我們今天就是要把中間點點點到底在幹嘛跟大家說一下。那就只是下面這樣而已.......

 

CGPROGRAM

 

struct of vertex 

 

struct of fragment (pixel)

 

vertex shader function

 

fragment shader function

 

ENDCG

 

結構上真的就這麼簡單,在說明結構之前,我們先稍微提一下基本圖學。

相信如果大家有上過圖學課,一定都知道,電腦3D得成像原理,而shader 就是這個成像原理的過程細節控制。

簡單的說,shader language 就是為了改變既有的3D成像過程而發明的,使之更加多變化。如果你圖學上的東西都還給老師的話,不用擔心因為我也是。如果你根本沒上過圖學,也沒關係,因為我接下來(應該)都不會提他。

 

所以我用下面一段文字來解是上面的架構:

我們在3D檔案(FBX, OBJ....)取得了所有vertex 的資料和資結,而用一個struct註冊了我們要用的資料變數(struct of vertex / 這個struct已經存好了3D檔案的資料,所以這些資料結構是固定的,你只是把他們撿出來用),然後在vertex shader fuction 中將這些資料作上一些空間轉換和任何可以做的數學操控,然後將結果輸出給struct of fragment,最後利用這個struct所提供的資料在fragment shader function中計算出最後該pixel 得 RGBA 值。

 

如果對上面那段話的解釋能夠理解,那你大概就會寫shader了吧...........(恩我是說大概)

然後我們回到圖學課(ㄟ剛剛不是說不提的吗....),大家發現了吧,projection 的過程,就夾在Vertex shader和fragment shader中間,首先,我們有了vertex資料後在vertex function中轉換了座標空間等的動作,將結果在傳遞給fragment function 去做頂點到頂點之間的內插計算出中間每一點的pixel色彩值。就像是魔法一樣,你完全不用知道詳細的過程,只需要知道怎麼完弄色彩就會變魔法了~這麼棒的事情你捨的不懂吗?

 

最後我們來解釋上一篇的 shader sample 作結尾吧

 

《Unity》Shader 02: CG的基礎結構

 

從properties 的宣告得知  我們有兩個使用者輸入的變數,顏色和一個2D才質

 

《Unity》Shader 02: CG的基礎結構

 

上面說明了subShader 開始,而每個subShader裡面都可以有無數個Pass,每個Pass 都會把該3D資料重畫,結果會覆蓋上一個Pass,所以這邊如果你用了多個Pass 就等於這個3D資料需要更多的draw calls 去畫他。所以沒事不要亂增加Pass。Pass 中才是真正的shader code,

第一行的 tag 在Unity 中有兩種意義可以作設定,一種是render type tag, 另一種是 render queue tag. 但這裡並不是說明這個畫出來的3D物件是不透明的。當然如果這裡把 Opaque 改成 Transprant 也不代表說你改了輸出的alpha 值就會變成半透明的,這裡的rendertype tag 跟後面的計算一點關係都沒有。Tag 的東西我們以後會開一集專講。接下來是LOD, level of detail 這個我也想開一集專講,現在就先知道,這是用於選擇subshader 得比較值。換言之,編寫者可以透過設定LOD來決定哪個平台要用哪個subshader。對得你沒看錯,shader 也可以做跨平台的最佳化。(shader lab 好棒棒!) 我之後會講方法和舉例子。

 

《Unity》Shader 02: CG的基礎結構

 

CGPROGRAM宣告了CG code 得開始

#pragma vertex vert 宣告會使用vertex shader function

#pragma fragment frag 宣告使用 fragment shader function

#pragma fragmention ARB.............. 這裡是說在處理fragment shader 的時候是使用較不精準的快速方法(通常都是用最快的)

#include "UnityCG.cginc" 這個東西 define 了很多針對Unity 得3D環境所設定的旗標,很好用,我們以後會常用。(http://wiki.unity3d.com/index.php/CGINCLUDE)

 

《Unity》Shader 02: CG的基礎結構

 

ㄟ 這邊的變數宣告好像在哪看過啊? 對的,在property 裡面。

只是你發現名稱雖然一樣,但是 class 不同。因為在CG 理最後計算結果是一個pixel 而已,所以是用採樣2D型別來取代2D。

而之前的color 為何不用 float4 而用 fixed4? 這也是為了快而犧牲精準度 float 是32 bit 的東西,而 fixed 只有大概12bit, 中間還有一個half,約莫是16bit. (寫shader 真是斤斤計較ㄟ)

 

《Unity》Shader 02: CG的基礎結構

 

這個struct 的宣告,存了兩個資料

第一個是頂點資料   寫法是

float4 vertex : POSITION

前面很明顯頂點的資料型別是float4 而後面的名稱你可以亂給,冒號後面跟得是,顯卡存頂點註冊位址(頂點資料固定是POSITION)

所以用到 appdata.vertex 運算的moment 真實的3D資料就傳進去了。

後面一樣啊,存的是貼圖的UV資訊

 

註冊的位址可以是

頂點顏色: COLOR

頂點:  POSITION

法向量:NORMAL

Tangent: TANGENT

其他的都可以存到,TEXCOORD0~ TEXCOORD15 (TEXCOORD8~15 是shader3.0才有的)

 

注意,這邊的資訊都生的,還沒進行空間轉換。

 

《Unity》Shader 02: CG的基礎結構

 

接下來是宣告fragment 得 struct  

一樣我們宣告了變數然後存在註冊的位址中

 

《Unity》Shader 02: CG的基礎結構

 

接下來在Vertex shader function 中轉換空間作標

UNITY_MATRIX_MVP 就是Unity.cginc 裡面定義的 Unity 的空間矩陣

然後把結果存到fragment struct得變數中

這邊有沒有偷偷發現TEXCOORD0 在原始的資料中代表的是第一組UV

當然如果你的3D資料有一組以上的UV 就會陸續被存在TEXCOORDX...

(小弟我的經驗是會常常用到第二組的)

 

《Unity》Shader 02: CG的基礎結構

 

最後要算fragment shader 了

tex2D 的結果就是RGBA,用美術的概念就是UV貼圖的結果,所以是sampler2D 在 UV空間上的值

最後乘上一開始的顏色值就是最後的結果了。

 

《Unity》Shader 02: CG的基礎結構

 

ㄟㄟ你唬我,這結果看不出明暗光線啊~恩,真的真心沒那東西。光影的變化,在shader 理也是計算出來的,

平常大家直接套用Unity 得builtin shader 時,都不會看到光的運算部分,是因為Unity 把那部分包起來成為"通用的部分"

既然是通用,就很耗運算資源。我們下一集會介紹省資源的遠距光怎麼寫進去,和normal map shader 得基礎寫法。

 

一樣如果發現上述內容有錯誤,有問題,等歡迎用任何方式讓我知道,謝謝。

※作者作品
《落跑藍圖》 Android

《落跑藍圖》iOS

x