OpenGL ES 2.0 知識串講 (6)——GLSL 語法(IV)

出處:電子設備中的畫家|王爍 於 2017 年 7 月 11 日發表,原文鏈接(http://geekfaner.com/shineengine/blog7_OpenGLESv2_6.html)

 

上節回顧

上面兩節,主要講解了 GLSL 中變量和函數的定義語法和使用語法,現在我們可以在 shader 中自定義一些我們所需要用到的變量和函數。但是在 shader 中, 還存在着一些內置的變量和函數。這些變量主要是用於將 Shader 計算得到的值傳給 GPU,完成 Shader 在 Pipeline 中的功能。由於我們使用 shader 的目的就是爲了把所需要的值傳給 GPU,所以這些變量對我們非常重要。

Shader 中內置的函數也非常重要,就好比 C 語言中的 printf 一樣,把我們想要使用到的功能用一個函數來包裝起來,這樣我們就可以更加方便的處理我們傳入的參數,以得到我們想要得到的結果。那麼這一節,我們將詳細的講解 GLSL 中的內置變量和函數。


GLSL 的內置變量

由於在 OpenGL ES 的 pipeline 中,Shader 最主要的功能就是計算出繪製的頂點位置信息和顏色信息,那麼這些信息需要由 Shader 傳給 GPU,所以就需要在 Shader 中定義特定的變量,用這些變量來保存這些特定的信息值,所以,在 Shader 中,包含有很多內置的變量。

在 shader 中,內置變量主要用於 VS 的輸出,PS 的輸入和輸出。然而針對 VS 的輸出和 PS 的輸入,內置變量與開發者自定義的 varying 變量不同。varying 變量本質上是在 VS 和 PS 中各定義一個名字類型一樣的變量,進行一一對應。而內置變量則是在 VS 和 PS 中都存在。

我們可以把內置變量再區分成,VS 中的內置變量以及 PS 中的內置變量。

gl_position

變量 gl_position 只存在於 VS 中,屬於 VS 中的內置變量。用法是在 VS 中,需要將頂點座標寫入這個變量。所有的 VS,都應該存在一個運算,就是把值寫入這個變量中。當然這個寫入的過程可以存在於 VS 的任何地方,寫入之後這個變量也是可以被讀取的。這個值非常重要,在 VS 結束之後,在 OpenGL ES 的 pipeline 中,在 GPU 光柵化的時候,這個值會被用於組元裝配,也就是把若干個點按照一定的規則組成三角形等形狀。根據這些頂點座標,進行裁剪(裁剪:判斷該像素點是否在我們的視口範圍內)、剔除(判斷該點是屬於物體的內表面還是外表面,根據規則可以不對物體的外表面或者內表面進行繪製,相應的頂點也就會被剔除掉)等操作。如果 gl_Position 沒有被賦值,或者在賦值之前就進行了讀取,編譯器會發現並提示。如果 gl_Position 沒有被賦值,那麼該變量爲 undefine。

gl_PointSize

變量 gl_PointSize,也是隻存在於 VS 中。屬於 VS 的內置變量,用於說明點的尺寸,這個尺寸的單位是像素,比如把這個變量設置爲 4,那麼就代表一個 2*2 的像素方塊是一個點。在做光珊化的時候,生成的新點也是 2*2 的像素方塊。舉個更容易想象的例子就是,打開畫圖工具,選擇畫直線,然後可以選擇線的粗細, 比如選擇細的線,畫出的可能就是用 1*1 的像素方塊構成的點組成的線,選擇粗的線,畫出的可能就是用 2*2 的像素方塊構成的點組成的線。這個變量也非常重要,但是區別於 gl_Position,gl_PointSize 如果不被賦值也不會出現畫不出來東西的情況。因爲如果不賦值的話,雖然該變量也是 undefine,但是在光珊化的時候, 會按照點的大小爲 1*1 的像素方塊來處理。所以在大部分情況下,gl_PointSize 是不需要被重新賦值的。

雖然這兩個變量是內置變量,不需要我們去定義它們,但是如果瞭解這兩個變量的定義方式,對我們更好的使用這兩個變量有很大的幫助。所以,借用我們上兩節學到的知識,gl_Position 本質上就是一個 vec4 變量,精度修飾符爲 highp, gl_PointSize 是一個 float 值,精度修飾符爲 mediump。

VS 中只有上述兩個內置變量。總結一下這兩個變量。如果沒有對他們進行賦值,那麼它們的值將爲 undefine。當對它們進行賦值之後,可以對它們進行讀取,讀取的是剛剛賦值進去的值。如果在賦值之前就進行讀取,那麼讀取到的就 是 undefine。如果對它們進行多次賦值,那麼它們最終的值就是最後一次賦予的值。它們在 VS 中都屬於全局變量。

下面說一下 PS 中的內置變量。

gl_FragColor gl_FragData

PS 的輸出參數,將會參與到 OpenGL ES 的固定管線中,而 PS 的輸出參數主要就是內置變量 gl_FragColor 和 gl_FragData。除非是在 PS 中調用到了 discard 這 個關鍵詞,否則該點經過 PS 計算出來的 gl_FragColor 或者 gl_FragData 將會被傳給 OpenGL ES。

雖然有 gl_FragColor 和 gl_FragData 兩種輸出參數,但是並沒有什麼要求指定必須用哪一個。

和 VS 中的內置變量有一點一樣,PS 中的這些變量也可以被賦值兩次,取最後一次被賦予的值傳給 OpenGL ES 進行固定管線的計算。這些變量被賦值之後, 可以對這些變量進行讀取,如果在賦值之前就進行讀取,就會得到 undefine。

對 gl_FragColor 進行賦值,顧名思義就是寫入該像素點的顏色,在 OpenGL ES 的固定管線中,如果在 PS 之後對像素顏色進行讀取,那麼獲取到的就是 PS 中 gl_FragColor 的值。如果在 PS 中沒有對 gl_FragColor 進行賦值,那麼像素顏色就是 undefine。

由於 gl_FragColor 和 gl_FragData 的作用不完全相同,且在 shader 中存在大量的算法,比如 shadowmap 或者 shadow volumn,這兩個算法都是用於計算陰影的,那麼它們需要使用同一個 VS,對應不同的 PS 進行多次繪製,其中會有一次繪製是爲了屏幕的高度圖,而不需要向顏色值中進行賦值。

在 PS 中,可以給 gl_FragColor 和 gl_FragData 中的任何一個值賦值,但是不能給它們兩個同時賦值。如果在 shader 中執行了 discard,那麼該像素就會被捨棄,gl_FragColor 和 gl_FragData 的值就會被捨棄。

gl_FragCoord

gl_FragCoord 相當於 PS 的輸入參數,是隻讀的。gl_FragCoord 是個 vec4,四個分量分別對應 x、y、z 和 1/w。其中,x 和 y 是當前片元的窗口相對座標,不過它們不是整數,小數部分恆爲 0.5。x - 0.5 和 y - 0.5 分別位於[0, windowWidth - 1]和[0, windowHeight - 1]內。windowWidth 和 windowHeight 都以像素爲單位,即 glViewPort 指定的寬高。gl_FragCoord.z 是固定管線計算出的當前片元的深度。它已經考慮了多邊形偏移,並經過了投影變換。它位於[0.0, 1.0]之間。如果用gl_FragColor = vec4(vec3(gl_FragCoord.z), 1.0)將其可視化,多半會看到一片白。這是由於變換的非線性,大多數點的深度都非常接近於 1。用 gl_FragColor = vec4(vec3(pow(gl_FragColor.z, exp)), 1.0)並將 exp 取爲合適的值,就能看到從黑到白的深度變化了。距離觀察者近的顏色深,接近 0.0;距離觀察者遠的顏色淺, 接近 1.0;gl_FragCoord.z / gl_FragCoord.w 可以得到當前片元和 camera 之間的距離。

gl_FrontFacing

gl_FrontFacing 也相當於 PS 的輸入參數,也是隻讀的,噹噹前像素屬於幾何體的正面的時候,gll_FrontFacing 爲 true。在 OpenGL ES 的 API 中我們可以設置哪些頂點屬於幾何體的正面,哪些屬於背面。這個參數的其中一個用法是:從兩種光照中選擇一個,來模仿物體的兩面光照。

gl_PointCoord

最後一個內置變量 gl_PointCoord 也相當於 PS 的輸入參數,也是隻讀的,是一個兩維座標,指出該點組元的當前像素點的位置,這個兩維座標已經被歸一化了,如果當前組元不是點,那麼 gl_PointCoord 爲 undefine。

下面介紹一下 PS 中內置變量的定義原型。

gl_FragColor 是一個 vec4,精度修飾符是 mediump。

gl_FragData 是一個數組,一共包含 gl_MaxDrawBuffers 個值。這裏說到了drawbuffer 的概念,我們在講 EGL 的時候,也說到了,OpenGL ES 需要向繪製 buffer 上繪製東西,這裏說的 drawbuffer,就是可以繪製的 buffer,也稱爲 RT(render target)。具體的解釋等我們說到 OpenGL ES 的時候再進行解釋說明。每個 gl_FragData 都是一個 vec4,精度修飾符也是 mediump。

gl_FragCoord 是個 vec4,精度修飾符是 mediump。

gl_FrontFacing 是一個 bool 值,bool 值是沒有精度修飾符的。

最後一個 gl_PointCoord 是 vec2,精度修飾符也是 mediump。

上一節我們介紹過存儲修飾符的功能就是用於說明它們和 VS、PS 之間的關係。雖然這些變量都沒有存儲修飾符,但是每個變量都已經詳細說明了它們的作用,誰是哪個 Shader 的輸入或者輸出。比如:gl_FragCoord 就是 PS 的輸入。

它們也都是全局變量。


GLSL 的內置常量

說完了 GLSL 中的內置變量,下面來說一下內置常量。

在 GLSL 中有一些被事先定義好的內置常量。

首先,介紹一下它們究竟是定義在哪裏,這裏需要回顧一下比 OpenGL ES 更底層的東西了。OpenGL ES 是 API,也就是一些函數,那麼這些函數肯定是有函數體的,這些函數體的定義,就是在 GPU 的 driver 中,可以認爲 GPU 的 driver 提供了 OpenGL ES 的庫,當然還定義了很多別的東西,比如剛纔說的 GLSL 的內置變量,以及現在要說的內置常量,還有一會要說的內置函數等。我們上一節說過,在 shader 中支持的 attribute、uniform 等都是有數量限制的,那麼這個數量可以通過 OpenGL ES 的 API 得到,然而這些數量也都是有限制的,不能說我這個硬件只支持 4 個 attibute,這樣是不行的,因爲 Khronos 對支持的 attribute 的最少數量也是有限制的,比如最少要支持 8 個 attribute,那麼這個限制其實是可以從 GLSL 的這些內置常量中得到。在 GPU driver 中,已經把能支持多少數量的 attibute 等,通過內置常量的形式進行了保存。開發者通過這些內置常量,就能得知這個設備至少支持多少個 attibute 之類的。

不管是 VS 還是 PS,都可以訪問這些內置常量。下面,來一一解釋一下這些內置常量。

gl_MaxVertexAttribs

這個比較容易理解,因爲我們知道存儲修飾符爲 attribute 的變量,只能存在於 VS 中,那麼這個意思就是 VS 中至少要支持不能超過 gl_MaxVertexAttribs 這麼多的 attribute,gl_MaxVertexAttribs 的定義是 8。剛纔這句話比較繞口,解釋一下,就是說我們知道在 Shader 中 attribute 是非常有用的,但是由於受到硬件的限制,一個 shader 中 attribute 的數量不能特別多,不能超過硬件的限制,那麼這裏就是一個 shader 中不能超過 8 個 attribute,那麼這個 8 又是 Khronos 定義給硬件廠商看的,意思就是硬件廠商在生產的時候可以生成超過 8 個位置給 attribute,比如可以說生成 16 個,生成 24 個,都沒有問題,但是不能少於 8 個, 如果少於 8 個,Khronos 是不會對這個硬件進行認可的。所以我們在開發的時候, 如果 attribute 的數量少於 8 個,就放心的使用,沒有問題,因爲所有的硬件,無 論什麼硬件,8 個都是可以支持的,但是如果某個開發者想要支持超過 8 個attribute,比如要在一個 shader 中使用 16 個 attribute,那麼需要用 OpenGL ES 的 API 先查詢一下,看當前設備是否支持 16 個 attribute。這個 API 等我們說 OpenGL ES API 的時候再進行說明。

gl_MaxVertexUniformVectors gl_MaxFragmentUniformVectors

上一節學到了 uniform 是可以存在於 VS 和 PS 中的,一般說,在 VS 中定義的 uniform,只能在 VS 中使用,在 PS 中定義的 uniform,只能在 PS 中使用。但假如在 VS 和 PS 中定義了一個變量名、修飾符都一樣的 uniform,那麼它們就是 一個 uniform。那麼對應於這兩個內置常量,第一個常量 gl_MaxVertexUniformVectors 定義了 VS 中至少需要支持不超過 gl_MaxVertexUniformVectors 個的 uniform , 第二個常量 gl_MaxFragmentUniformVectors 定義了 PS 中至少需要支持不超 過 gl_MaxFragmentUniformVectors 個的 uniform。而且 uniform 我們知道是支持多種數量類型的,比如 float,比如 vec3,比如 mat4。上一節也說了,一個 mat4 的 uniform 佔用了 4 個 vec4 的位置。在這裏 gl_MaxVertexUniformVectors 爲 128, gl_MaxFragmentUniformVectors 爲 16。也就是說在 VS 中,支持 128 個 vec4,但 是如果使用了 129 個 float 的 uniform,那麼就出錯了,支持 128 除以 4 等於 32 個 mat4 的 uniform,但是如果使用了 33 個 mat4 的 uniform 也就出錯了。

gl_MaxVaryingVectors

varying 變量同時存在於 VS 和 PS 中才算有意義,所以這裏也就不區分 VS 還 是 PS 了。那麼這裏也就是在一對 shader 中,最多隻能存在 gl_MaxVaryingVectors 個 varying 變量,計量標準也是 vec4。

補充一句,剛纔我們說了針對 attribute、uniform 和 varying 變量的限制,但是我們之前也說了假如定義了卻沒有使用的 attribute、uniform、varying,以及其他一些非 static use 的話,那麼這些變量的定義是無效的,也就是不會被計入這種計算限制的數量中。也就是說我們就是在 VS 中定義了 10000 個 uniform,但是我們沒有使用,shader 也就把它們優化掉,就相當於沒有定義,在使用這個 shader 的時候也就不會出錯。

我們知道在 OpenGL ES 中紋理非常重要,但是 texture 的使用也是受到限制的。紋理的使用比較複雜,並非我們想象中,直接顯示使用幾張 texture。紋理其實首先要被放到 texture unit 裏面,然後把 texture unit 傳入 shader。雖然說 OpenGL ES API 的時候我們還會詳細介紹 texture unit,但是這裏,我們還是先簡單的解釋一下。texture 在 OpenGL ES 中分爲兩種,一種是 2D 的,一種是 CubeMap 的,texture unit 類似於一個容器,一個 texture unit 中,每種 texture 可以各放一張,也就是 texture unit 中最多可以包含兩張不同類型的 texture,如果再往裏面放的話,就會把之前的 texture 覆蓋掉。然後把 texture unit 往 shader 中傳送的時候,在一套 shader 中,只能使用其中的一張 texture。

gl_MaxVertexTextureImageUnits

指的是 VS 中最多的 texture unit 的數量,這個內置常量被定義爲了 0,可能是因爲 Khronos 認爲 VS 中不使用 texture 也沒關係,也確實 texture 基本是被使用在 PS 中的。

gl_MaxCombinedTextureImageUnits

一般 texture 都是被作爲 uniform 傳入,這個也可以理解,因爲 texture 基本是在 PS 中使用的,如果通過 attribute 傳入,然後再通過 varying 傳給 PS,一個是比較複雜,另外一個 Varying 是需要被光珊化的,所以 Varying 越少,對性能越好。那麼 texture 基本都是 uniform,而作爲 uniform,就存在剛纔我們也提到的那個機制,就是 VS 和 PS 中的兩個完全一樣的 uniform 被認爲是一個 uniform, 這裏我們稱之爲 combine,也就是 VS 和 PS 中共同定義的 texture unit 的數量,最多是 8。

gl_MaxTextureImageUnits

指的是 shader 中 texture unit 的數量。

gl_MaxDrawBuffers

指的是最多可支持的繪製 buffer,繪製 buffer 的概念我們就不再重複了。一般情況下 OpenGL ES2.0 中,只使用一個 draw buffer 的,在這裏 khronos 也把這個常量定義爲了 1。而在 OpenGL ES 3.0 中開啓了一個新的概念 MRT,就是同時有多個繪製 buffer,這個等我們以後開 OpenGL ES 3.0 的課程的時候再進行說明。

gl_DepthRange

最後還有一個特殊的內置變量,一個內置的 uniform 。剛纔我們說的內置常量和變量,都是獨立於 attribute、varying、uniform 之外的,而這個變量,就是一個 uniform。使用起來好比一個我們正常定義的 uniform,可以通過 OpenGL ES API 得到它的 location,然後傳值進入。這個 uniform 就是 gl_DepthRange,類型是一個 struct gl_DepthRangeParameters,該 struct 有三個成員變量,分別是 near、far、 diff。

// Depth range in window coordinates

struct gl_DepthRangeParameters

{

highp float near; // n

highp float far; // f

highp float diff; // f – n

};

}uniform gl_DepthRangeParameters gl_DepthRange;

這三個成員變量都是 float 的,精度修飾符都是 high,但是由於默認 PS 是不支持 high 的,所以在這些設備中,這三個成員變量就相當於精度修飾符爲 mediump。這個變量是用於存放在三維空間中的視野空間中的深度範圍。具體的等我們在 OpenGL ES 中說到的時候再進行解釋說明。在這裏我們只需要知道這個內置 uniform 佔用了一個 uniform 的名額。就好比剛纔我們知道 VS 中只能有 128 個 uniform,那麼除去這一個,我們開發者只能再定義 127 個 uniform 了。

GLSL 中是沒有內置 attribute 和 varying 的。


GLSL 的內置函數

GLSL 中定義了若干系列非常好用的內置函數,這些內置函數有一部分是在 VS 和 PS 中都可以被使用的,但是也有一部分是隻能使用在某種 shader 中的。

內置函數大體上可以分爲三種類型:

第一種函數提供了一種方便的方式,用於處理對硬件的操作,比如對紋理的處理。在 shader 中,開發者沒有辦法使用任何一種方式去替代這類函數,因爲這類函數中涉及到了對硬件的操作。

第二種函數其實只提供了一些簡單的平常的運算,比如 clamp 等,這些運算開發者可以很輕鬆的實現。但是由於這些運算很常用,所以提供一個統一的庫就省去了開發者自己寫的時間。而且也可以 GPU 內部的硬件做一定的優化,比如指數運算,通過彙編來實現句,如果交給普通的硬件處理就很複雜,而使用優化後對應的硬件去實現,就會很簡單。

第三種函數是使用 GPU 硬件去實現一些函數,這樣會對這些運算進行提速,比如三角運算。

大部分函數都類似於 C 語言中的同名函數,只是這些函數的輸入支持 vector,比如 vec4 或者 mat4,而不僅僅是標量輸入。

開發者被鼓勵使用內置函數。開發者可以重載這些內置函數,但是不能對這些函數進行重寫。

在這些內置函數的聲明中沒有註明精度修飾符,但是針對 texture 運算,返回類型的精度和 sample 類型的精度一致。其他精度修飾符的規則我們在上個課時講精度修飾符的時候也進行過詳細的說明。返回值的精度修飾符與輸入參數的最高精度修飾符一致。

下面,我們來具體的說一下內置函數。

Angle and Trigonometry Functions

三角函數。比如角度和弧度的變換,弧度也就是角度除以 180 再乘以派。再比如常用的正弦,餘弦,正切,反正切,反正弦,反餘弦。假如 x 的正弦是 y, 那麼 y 的反正弦爲 x,這些函數就不進行具體介紹了。

Exponential Functions

指數預算。比如 pow 函數,傳入 x 和 y 得到 x 的 y 次方。比如 exp 函數,傳入x得到e的x次方。比如log函數,傳入x得到log x,假如得到的結果是y, 也就是 e 的 y 次方是 x。比如 exp2 函數,也就是返回 2 的 x 次方。log2 函數,傳入 x 返回 log2 x,假如得到的結果是 y,也就是 2 的 y 次方是 x。sqrt 函數,開根號函數,傳入 x 得到根號 x。inversesqrt 函數,開根號然後求倒數,傳入 x 得到 根號 x 分之 1。

Common Functions

普通的運算函數。比如 abs 取絕對值的函數。sign 取符號的函數,比如傳入的 x 大於 0,則得到 1,等於 0 得到 0,小於 0,得到-1。floor 函數,也就是得到最接近且小於或者等於 x 的值。比如 4.6 則得到 4,-4.6 則得到-5。ceil 函數,於 floor 函數相反,得到最接近且大於或者等於 x 的值。比如 4.4 得到 5,- 4.4 得到-4。fract 函數,得到 x-floor(x),也就是 4.6 的話會得到 4.6-4=0.6。

mod 函數,傳入 x 和 y,得到 x - y * floor(x/y)。min 和 max 函數,傳入 x 和 y,得 到 x 和 y 中的最小值或者最大值。clamp 函數,傳入 x 和 min 和 max 三個參數, 如果 x 在 min 和 max 之間,返回 x,如果 x 比 min 小,得到 min,如果 x 比 max 大,得到 max,但是如果 min 大於 max,得到 undefine。mix 函數,傳入三個參 數 x,y 和 a,得到 x*(1-a) + y*a。step 函數,傳入參數 x 和 y,如果第一個參數小於第二個參數則返回 0,否則返回 1。smoothstep 函數,傳入三個參數 a,b, x,如果 x 小於等於 a,得到 0,如果 x 大於等於 b,得到 1,如果 a<x<b,則按照一定規則進行插值,如果 a 大於或者等於 b,則返回 undefine。

Geometric Functions

幾何運算。比如 length 函數,求長度,假如傳入一個 vec3 的 a,那麼得到的就是 a.x 的平方+a.y 的平方+a.z 的平方得到的結果開根號。distance 函數,求距離,假如傳入兩個 vec3 a 和 b,得到就是 a-b 得到的 vec3 變量的 length。dot 函數,求兩個向量的點積,假如傳入兩個 vec3 a 和 b,得到就是 a.x*b.x+a.y*b.y +a.z*b.z。cross 函數,求兩個向量的叉積。normalize 函數,歸一化函數,比如傳入一個向量 vec3 x,那麼把 x 的三個分量分別除以 a 的長度,得到的 vec3 就是結果。faceforward,傳入三個參數,a b c,假如 b 和 c 的點積小於 0,返回 a, 否則返回-a。reflect 函數,得到反射向量。refract 函數,得到折射向量,這兩個函數屬於光照方面的函數,算法比較複雜,在這裏我就不具體說了。

Matrix Functions

內置的矩陣運算只有一個,matrixCompMult,傳入兩個矩陣,計算乘法,得到他們的乘積。

Vector Relational Functions

內置的 Vec 運算有很多,可能是因爲 shader 中絕大多數都是 vec 操作。比如比較函數中的小於函數,小於等於函數,大於函數,大於等於函數,等於函數和不等於函數。any 函數,傳入一個 bvec,這裏的 bvec 可以是 bvec2、bvec3、bvec4. 那麼假如其中一個成員爲 true,any 函數爲 true。all 函數,只有所有的成員都是 true,all 函數纔是 true。not 函數,返回一個於傳入參數完全相反的 bvec。

Texture Lookup Functions

最後一種內置函數,是 texture 相關的內置函數。也就是在 VS 和 PS 中訪問texture 的函數。最常規的函數就是 texture2D,傳入一個 texture 的 sample,和一個紋理座標,這樣可以得到紋理的像素點對應到圖片上。這個函數還可以再傳一個 bias,bias 是用於計算 lod 的。因爲 texture 可以通過 mipmap 分爲很多層,從小到大,小的圖片精度低但是使用起來效率快,大的圖片精度高,但是使用起來耗能。bias 就是 lod 的 bias,決定取哪層 mipmap 的。假如有 bias,且開啓了紋理的mipmap功能(使用glGeneratemipmap生成該紋理的mipmap數據,或者使用glTexImage2D定義了該紋理所有層mipmap信息,同時該紋理的minfilter設置爲帶mipmap的參數;如果沒有使用glGenerateMipmap,而是使用glTexImage2D生成數據,但是又沒有生成所有mipmap層次的數據,假如minfiler設置爲帶mipmap的參數,則顯示黑色。),那麼就先計算應該用哪層 mipmap,然後再根據bias進行偏移,比如當前應該使用第1層mipmap,而bias爲1,那麼則使用第2層mipmap數據,如果bias爲-1,則使用第0層mipmap數據。如果沒有 bias,且 texture 沒有 mipmap,則 texture 直接使用,如果有 mipmap,那麼在 PS 中則使用應該使用的那層 mipmap,在 VS 中則使用 base texture。 texture2DProj 函數,傳入的紋理座標區別於剛纔的 vec2,而使用 vec3 和 vec4。 與剛纔紋理座標的區別是,這裏雖然傳入 vec3 或者 vec4,但是也是當作 vec2 使 用的,只是前兩個成員會除以 vec3 或者 vec4 的最後一個成員,這裏也可以傳入 bias。texture2DProjLod 函數,這種函數只能在 VS 中使用。這些是 2D 的 texture, CubeMap 的 texture 也類似的有幾種函數,texturecube 和 texturecubelod,就不一一介紹了。

通過以上這四節的學習,對 GLSL 的語法進行了詳細的串講。

首先學習了 GLSL 中的預處理和註釋。

然後,學習了 GLSL 中變量的基本知識,包括變量的類型,其中有標量類型、向量類型還有複雜類型等,講了如何定義變量、初始化變量,對變量進行操作,以及從哪裏獲取變量的範圍。

再然後,講解了變量的修飾符,包括 4 種,存儲修飾符確定作用域和作用, 參數修飾符確定變量是函數的傳入還是傳出參數,精度修飾符確定精度, variance 修飾符確定變量是否是恆定的。

最後,講解了 GLSL 中的內置變量、常量和函數,這些非常重要且有用,對它們進行充分理解之後,GLSL 最重要的語法和目的就基本上全部掌握了。

本節教程就到此結束,希望大家繼續閱讀我之後的教程。

謝謝大家,再見!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章