1. 程式人生 > >[WebGL入門]八,著色器的說明和基礎

[WebGL入門]八,著色器的說明和基礎

注:文章譯自http://wgld.org/,原作者杉本雅広(doxas),文章中如果有我的額外說明,我會加上[lufy:],另外,鄙人webgl研究還不夠深入,一些專業詞語,如果翻譯有誤,歡迎大家指正。

認識GLSL

WebGL是無法利用固定渲染管線的,這個在之前的文章(四,渲染準備)裡已經簡單的說明過了。
所以,代替它的是可編輯渲染管線中的一種著色語言,叫做GLSL(OpenGL Shading Language)。

是用來在OpenGL中著色程式設計的語言,GLSL使用C語言為基礎,並且有自己獨立的語法。WebGL的難點之一,就是這個GLSL,不理解GLSL的話,就無法進行渲染。所以,學習WebGL不但要學習WebGL的基本知識,還需要了解GLSL,有點抓狂了吧。

但是,如果只做一些基本的東西的話,也不太難。等習慣了之後,能夠自己編寫著色器的話會有很大的好處。這一點要慢慢來,不能太著急。

著色器的作用

GLSL的知識不用從零開始徹底理解,只需要先了解一下最基本的東西就行。細節部分,留到後面再講,先把基本的部分徹底理解。

*下面開始,我用最容易理解的方式來介紹,所以會簡化很多東西。

首先,WebGL裡有頂點著色器和片段著色器兩種著色器。無論哪一種都可以使用GLSL來編寫。頂點著色器和片段著色器是相互依賴的,缺一不可,並且首先被呼叫的是頂點著色器。

可以把頂點相關的所有情報都傳給頂點著色器。比如,頂點的位置,頂點法線,紋理座標,頂點顏色等等,跟頂點相關的所有情報都可以傳給頂點著色器。在這裡,你可以自由決定傳入著色器的內容,這種靈活性就是可編輯渲染管線的好處。但是,雖然說傳入著色器的內容是自由決定的,但是頂點的位置情報是必須的,因為如果不知道

頂點的位置的話,是沒有辦法繪製模型的。

頂點著色器就跟它的字面上的意思一樣,接受頂點相關的情報,最後決定如何處理這些頂點。而片段著色器則決定了畫面上用什麼顏色來輸出。片段著色器的英文是fragment,其實就是斷片,碎片的意思。而畫面上的畫素則是畫面上的最小的斷片,所以片段著色器操作的是顏色。

再簡單一點說明的話,頂點著色器就是處理頂點相關的資訊,片段著色器就是處理畫面上的顏色資訊。

GLSL的編寫基礎

好了,已經理解了著色器是幹什麼的了吧,下面接著來看一下GLSL的編寫方法。

首先,不管是頂點著色器還是片段著色器,都必須定義一個main函式,函式裡記錄你要做的處理。而且,頂點著色器的話,必須要把頂點資訊傳給一個叫做gl_Position的變數。

比如下面是一個非常簡單的頂點著色器的例子。

attribute vec3 position;

void main(void) {
    gl_Position = position;
}
這裡出現了一個奇怪的單詞吧,最上面一行裡的attribute是個什麼東東呢?
其實,就是用來宣告變數的,用這個修飾符來定義的變數(上面的position),是用來接收頂點情報的。也就是說,上面的程式碼,WebGL程式中定義一個position,做一些處理之後,傳給著色器。

再稍微說明一下,attribute修飾符是用來接收不同頂點傳來的不同資訊。如果存在很多個頂點的話,這些頂點的位置是不同的吧。用來接收這些不同頂點的不同資訊的機制,用attribute修飾符來定義變數。

座標變換也用GLSL

剛才說了,頂點著色器是處理頂點相關的資訊,但是不要忘了,頂點相關的處理就是座標變換。模型變幻,檢視變換,投影變換這三個變換也是頂點著色器的工作之一。

基本上,用頂點著色器來做什麼是比較自由的,但是在WebGL程式中,首先生成模型,檢視,投影的各個矩陣,然後進行合併,最後將得到的座標變換的矩陣傳給頂點著色器,這是一般的做法。

那麼,考慮一下,這個座標變換的矩陣怎麼樣傳給頂點著色器比較好呢?

使用之前的attribute嗎,但是attribute是傳遞不同頂點的不同情報的。而座標變換矩陣對於所有頂點來說都是相同的,使用attribute修飾符就有點奇怪了。

這個時候使用的修飾符是uniform。使用uniform修飾符的話,可以傳遞對於所有頂點一致的處理的情報。基於這一點,來修改一下剛才的程式碼吧。*只是一個示例。

attribute vec3 position;
uniform mat4 mvpMatrix;

void main(void) {
    gl_Position = mvpMatrix * position;
}
這裡出現的mvpMatrix,是模型,檢視,投影的各個變換矩陣結合後的矩陣。從WebGL一側將這個座標變換矩陣傳給通過用uniform修飾符定義的變數。
>>GLSL中可以使用的型別

剛才給出的程式碼例子中,修飾符後面還跟著vec3和mat4等,這是變數的型別。這裡只是代表一下,簡單接觸一下。

vec*表示的是向量,*的部分是一個24的數字,vec2就代表一個2維的向量。

mat*表示的是方陣,和向量一樣,可以指定的範圍也是24,如果是mat3的話,就表示一個3x3的方陣。

另外,int是整型,float是浮點型,bool是布林型,這些都跟C語言中是一個意思。vec*和mat*中的元素,都是浮點型。

與片段著色器的連線

雖然寫的有點長了,但是再稍微加點東西。attribute和uniform這兩個修飾符已經理解了吧。

GLSL裡面還有一個特別重要的修飾符,就是varying修飾符。這個varying修飾符,是頂點著色器和片段著色器之間的橋樑。

舉個例子,要把繪製的模型變成半透明,要怎麼做呢?

方法雖然有很多,但是一般的做法是,向頂點裡新增顏色的情報資訊,然後通過操作顏色的透明度的變化來使模型半透明或者完全透明。這時候,如果想操作頂點裡的顏色資訊和畫面上的顏色資訊的話,就需要向片段著色器裡傳入一些必要的資訊。

可是要怎麼傳遞這些資訊呢?這時候就用到varying了。根據前面給的程式碼例子,再稍微修改一下,這一次不光有頂點著色器,片段著色器也一起寫進去。

首先,頂點著色器部分。

attribute vec4 position;
attribute vec4 color;
uniform mat4 mvpMatrix;
varying vec4 vColor

void main(void) {
    vColor = color;
    gl_Position = mvpMatrix * position;
}
接著,片段著色器接收通過varying修飾符所定義的變數vColor。
varying vec4 vColor;

void main(void)
{
    gl_FragColor = vColor;
}
就是這樣,要從頂點著色器將資料傳到片段著色器,需要使用varying修飾符所定義的變數。另外,和頂點著色器中必需要把資料傳給gl_Position類似,片段著色器要把資料傳給gl_FragColor。

與頂點著色器不同的是,片段著色器的gl_FragColor不是必須要賦值的。但是一般都會輸出一種什麼顏色,所以gl_FragColor就變成必要的了。

總結

這次的內容有點太長了,介紹的內容也有點深,一次性全都理解可能會有點兒難吧。

簡單的把這次的內容總結一下。

頂點著色器和片段著色器,都可以通過GLSL來書寫,基本上它們算是一個組合。著色器的內部,必須要定義一個main函式,在這個函式裡面新增自己的處理。而且,要從WebGL一側向著色器傳遞資料的時候,需要用到一些特殊的修飾符所定義的變數。

要向著色器傳遞各個頂點的不同的資訊的時候,使用attribute修飾符宣告變數,要向著色器傳遞對所有頂點來說都一樣的資訊的時候,使用uniform修飾符宣告變數。

另外,從頂點著色器向片段著色器傳遞資料的時候,使用varying修飾符宣告變數。

頂點著色器中內建的變數gl_Position必須賦值,而片段著色器的內建變數gl_FragColor雖然不是必須賦值的,但是一般情況下都會賦值。

關於GLSL,正式的內容的話是很深的,這次的內容是算是介紹了一些表層的最基本的部分。和這些相關的內容,以後會逐漸接觸到,到時候再慢慢的說明。首先,把這次的內容徹底理解一下吧。

下次,介紹頂點快取相關的內容。