圖形處理之Shader語言(一)GLSL語法篇
變數
GLSL的變數命名方式與C語言類似。變數的名稱可以使用字母,數字以及下劃線,但變數名不能以數字開頭,還有變數名不能以gl_作為字首,這個是GLSL保留的字首,用於GLSL的內部變數。當然還有一些GLSL保留的名稱是不能夠作為變數的名稱的。
基本型別
除了布林型,整型,浮點型基本型別外,GLSL還引入了一些在著色器中經常用到的型別作為基本型別。這些基本型別都可以作為結構體內部的型別。如下表:
型別 | 描述 |
void | 跟C語言的void類似,表示空型別。作為函式的返回型別,表示這個函式不返回值。 |
bool | 布林型別,可以是true 和false,以及可以產生布爾型的表示式。 |
int | 整型 代表至少包含16位的有符號的整數。可以是十進位制的,十六進位制的,八進位制的。 |
float | 浮點型 |
bvec2 | 包含2個布林成分的向量 |
bvec3 | 包含3個布林成分的向量 |
bvec4 | 包含4個布林成分的向量 |
ivec2 | 包含2個整型成分的向量 |
ivec3 | 包含3個整型成分的向量 |
ivec4 | 包含4個整型成分的向量 |
mat2 或者 mat2x2 | 2x2的浮點數矩陣型別 |
mat3或者mat3x3 | 3x3的浮點數矩陣型別 |
mat4x4 | 4x4的浮點矩陣 |
mat2x3 | 2列3行的浮點矩陣(OpenGL的矩陣是列主順序的) |
mat2x4 | 2列4行的浮點矩陣 |
mat3x2 | 3列2行的浮點矩陣 |
mat3x4 | 3列4行的浮點矩陣 |
mat4x2 | 4列2行的浮點矩陣 |
mat4x3 | 4列3行的浮點矩陣 |
sampler1D | 用於內建的紋理函式中引用指定的1D紋理的控制代碼。只可以作為一致變數或者函式引數使用 |
sampler2D | 二維紋理控制代碼 |
sampler3D | 三維紋理控制代碼 |
samplerCube | cube map紋理控制代碼 |
sampler1DShadow | 一維深度紋理控制代碼 |
sampler2DShadow | 二維深度紋理控制代碼 |
結構體
結構體
結構體可以組合基本型別和陣列來形成使用者自定義的型別。在定義一個結構體的同時,你可以定義一個結構體例項。或者後面再定義。
structsurface {float indexOfRefraction;
vec3 color;float turbulence;
} mySurface;
surface secondeSurface;
你可以通過=為結構體賦值,或者使用 ==,!=來判斷兩個結構體是否相等。
mySurface = secondSurface;
mySurface == secondSurface;
只有結構體中的每個成分都相等,那麼這兩個結構體才是相等的。訪問結構體的內部成員使用. 來訪問。
vec3 color = mySurface.color + secondSurface.color;
結構體至少包含一個成員。固定大小的陣列也可以被包含在結構體中。GLSL的結構體不支援巢狀定義。只有預先宣告的結構體可以巢狀其中。
struct myStruct {
vec3 points[3]; //固定大小的陣列是合法的
surface surf; //可以,之前已經定義了
struct velocity { //不合法float speed;
vec3 direction;
} velo;
subSurface sub; //不合法,沒有預先宣告;};struct subSurface { int id;
};
陣列
GLSL中只可以使用一維的陣列。陣列的型別可以是一切基本型別或者結構體。下面的幾種陣列宣告是合法的:
surface mySurfaces[];
vec4 lightPositions[8];
vec4 lightPos[] = lightPositions;const int numSurfaces = 5;
surface myFiveSurfaces[numSurfaces];float[5] values;
指定顯示大小的陣列可以作為函式的引數或者使返回值,也可以作為結構體的成員.陣列型別內建了一個length()函式,可以返回陣列的長度。
lightPositions.length() //返回陣列的大小 8
最後,你不能定義陣列的陣列。
修飾符
變數的宣告可以使用如下的修飾符。
修飾符 | 描述 |
const | 常量值必須在宣告是初始化。它是隻讀的不可修改的。 |
attribute | 表示只讀的頂點資料,只用在頂點著色器中。資料來自當前的頂點狀態或者頂點陣列。它必須是全域性範圍宣告的,不能再函式內部。一個attribute可以是浮點數型別的標量,向量,或者矩陣。不可以是陣列或則結構體 |
uniform | 一致變數。在著色器執行期間一致變數的值是不變的。與const常量不同的是,這個值在編譯時期是未知的是由著色器外部初始化的。一致變數在頂點著色器和片段著色器之間是共享的。它也只能在全域性範圍進行宣告。 |
varying | 頂點著色器的輸出。例如顏色或者紋理座標,(插值後的資料)作為片段著色器的只讀輸入資料。必須是全域性範圍宣告的全域性變數。可以是浮點數型別的標量,向量,矩陣。不能是陣列或者結構體。 |
centorid varying | 在沒有多重取樣的情況下,與varying是一樣的意思。在多重取樣時,centorid varying在光柵化的圖形內部進行求值而不是在片段中心的固定位置求值。 |
invariant | (不變數)用於表示頂點著色器的輸出和任何匹配片段著色器的輸入,在不同的著色器中計算產生的值必須是一致的。所有的資料流和控制流,寫入一個invariant變數的是一致的。編譯器為了保證結果是完全一致的,需要放棄那些可能會導致不一致值的潛在的優化。除非必要,不要使用這個修飾符。在多通道渲染中避免z-fighting可能會使用到。 |
in | 用在函式的引數中,表示這個引數是輸入的,在函式中改變這個值,並不會影響對呼叫的函式產生副作用。(相當於C語言的傳值),這個是函式引數預設的修飾符 |
out | 用在函式的引數中,表示該引數是輸出引數,值是會改變的。 |
inout | 用在函式的引數,表示這個引數即是輸入引數也是輸出引數。 |
內建變數
內建變數可以與固定函式功能進行互動。在使用前不需要宣告。頂點著色器可用的內建變數如下表:
名稱 | 型別 | 描述 |
gl_Color | vec4 | 輸入屬性-表示頂點的主顏色 |
gl_SecondaryColor | vec4 | 輸入屬性-表示頂點的輔助顏色 |
gl_Normal | vec3 | 輸入屬性-表示頂點的法線值 |
gl_Vertex | vec4 | 輸入屬性-表示物體空間的頂點位置 |
gl_MultiTexCoordn | vec4 | 輸入屬性-表示頂點的第n個紋理的座標 |
gl_FogCoord | float | 輸入屬性-表示頂點的霧座標 |
gl_Position | vec4 | 輸出屬性-變換後的頂點的位置,用於後面的固定的裁剪等操作。所有的頂點著色器都必須寫這個值。 |
gl_ClipVertex | vec4 | 輸出座標,用於使用者裁剪平面的裁剪 |
gl_PointSize | float | 點的大小 |
gl_FrontColor | vec4 | 正面的主顏色的varying輸出 |
gl_BackColor | vec4 | 背面主顏色的varying輸出 |
gl_FrontSecondaryColor | vec4 | 正面的輔助顏色的varying輸出 |
gl_BackSecondaryColor | vec4 | 背面的輔助顏色的varying輸出 |
gl_TexCoord[] | vec4 | 紋理座標的陣列varying輸出 |
gl_FogFragCoord | float | 霧座標的varying輸出 |
片段著色器的內建變數如下表:
名稱 | 型別 | 描述 |
gl_Color | vec4 | 包含主顏色的插值只讀輸入 |
gl_SecondaryColor | vec4 | 包含輔助顏色的插值只讀輸入 |
gl_TexCoord[] | vec4 | 包含紋理座標陣列的插值只讀輸入 |
gl_FogFragCoord | float | 包含霧座標的插值只讀輸入 |
gl_FragCoord | vec4 | 只讀輸入,視窗的x,y,z和1/w |
gl_FrontFacing | bool | 只讀輸入,如果是視窗正面圖元的一部分,則這個值為true |
gl_PointCoord | vec2 | 點精靈的二維空間座標範圍在(0.0, 0.0)到(1.0, 1.0)之間,僅用於點圖元和點精靈開啟的情況下。 |
gl_FragData[] | vec4 | 使用glDrawBuffers輸出的資料陣列。不能與gl_FragColor結合使用。 |
gl_FragColor | vec4 | 輸出的顏色用於隨後的畫素操作 |
gl_FragDepth | float | 輸出的深度用於隨後的畫素操作,如果這個值沒有被寫,則使用固定功能管線的深度值代替 |
表示式
操作符
GLSL語言的操作符與C語言相似。如下表(操作符的優先順序從高到低排列)
操作符 | 描述 |
() | 用於表示式組合,函式呼叫,構造 |
[] | 陣列下標,向量或矩陣的選擇器 |
. | 結構體和向量的成員選擇 |
++ -- | 字首或字尾的自增自減操作符 |
+ – ! | 一元操作符,表示正 負 邏輯非 |
* / | 乘 除操作符 |
+ - | 二元操作符 表示加 減操作 |
<> <= >= == != | 小於,大於,小於等於, 大於等於,等於,不等於 判斷符 |
&& || ^^ | 邏輯與 ,或, 異或 |
?: | 條件判斷符 |
= += –= *= /= | 賦值操作符 |
, | 表示序列 |
像 求地址的& 和 解引用的 * 操作符不再GLSL中出現,因為GLSL不能直接操作地址。型別轉換操作也是不允許的。 位操作符(&,|,^,~, <<, >> ,&=, |=, ^=, <<=, >>=)是GLSL保留的操作符,將來可能會被使用。還有求模操作(%,%=)也是保留的。
陣列訪問
陣列的下標從0開始。合理的範圍是[0, size - 1]。跟C語言一樣。如果陣列訪問越界了,那行為是未定義的。如果著色器的編譯器在編譯時知道陣列訪問越界了,就會提示編譯失敗。
vec4 myColor, ambient, diffuse[6], specular[6];
myColor = ambient + diffuse[4] + specular[4];
建構函式
建構函式可以用於初始化包含多個成員的變數,包括陣列和結構體。建構函式也可以用在表示式中。呼叫方式如下:
vec3 myNormal = vec3(1.0, 1.0, 1.0);
greenTint = myColor + vec3(0.0, 1.0, 0.0);
ivec4 myColor = ivec4(255);
還可以使用混合標量和向量的方式來構造,只要你的元素足以填滿該向量。
vec4 color = vec4(1.0, vec2(0.0, 1.0), 1.0);
vec3 v = vec3(1.0, 10.0, 1.0);
vec3 v1 = vec3(v);
vec2 fv = vec2(5.0, 6.0);
對於矩陣,OpenGL中矩陣是列主順序的。如果只傳了一個值,則會構造成對角矩陣,其餘的元素為0.
mat3 m3 = mat3(1.0);
構造出來的矩陣式:
1.0 0.0 0.0
0.0 1.0 0.0
0.0 0.0 1.0
mat2 matrix1 = mat2(1.0, 0.0, 0.0, 1.0);
mat2 matrix2 = mat2(vec2(1.0, 0.0), vec2(0.0, 1.0));
mat2 matrix3 = mat2(1.0);
mat2 matrix4 = mat2(mat4(2.0)); //會取 4x4矩陣左上角的2x2矩陣。
建構函式可以用於標量資料型別的轉換。GLSL不支援隱式或顯示的轉換,只能通過建構函式來轉。其中int轉為float值是一樣的。float轉為int則小數部分被丟棄。int或float轉為bool,0和0.0轉為false,其餘的值轉為true. bool轉為int或float,false值轉為0和0.0,true轉為1和1.0.
float f = 1.7;
int I = int(f); // I = 1
陣列的初始化,可以在建構函式中傳入值來初始化陣列中對應的每一個值。
ivec2 position[3] = ivec2[3]((0,0), (1,1), (2,2));
ivec2 pos2[3] = ivec2[]((3,3), (2,1), (3,1));
建構函式也可以對結構體進行初始化。其中順序和型別要一一對應。
structsurface { int index;
vec3 color; float rotate;
};
surface mySurface = surface(3, vec3(red, green, blue), 0.5);
成分選擇
向量中單獨的成分可以通過{x,y,z,w},{r,g,b,a}或者{s,t,p,q}的記法來表示。這些不同的記法用於頂點,顏色,紋理座標。在成分選擇中,你不可以混合使用這些記法。其中{s,t,p,q}中的p替換了紋理的r座標,因為與顏色r重複了。下面是用法舉例:
vec3 myVec = {0.5, 0.35, 0.7};float r = myVec.r;float myYz = myVec.yz;float myQ = myVec.q;//出錯,陣列越界訪問,q代表第四個元素float myRY = myVec.ry; //不合法,混合使用記法
較特殊的使用方式,你可以重複向量中的元素,或者顛倒其順序。如:
vec3 yxz = myVec.yxz; //調換順序vec4 mySSTT = myVec.sstt; //重複其中的值
在賦值是,也可以選擇你想要的順序,但是不能重複其中的成分。
vec4 myColor = {0.0, 1.0, 2.0, 1.0};
myColor.x = -1.0;
myColor.yz = vec2(3.0, 5.0);
myColor.wx = vec2(1.0, 3.0);
myColor.zz = vec2(2.0, 3.0); //不合法
我們也可以通過使用下標來訪問向量或矩陣中的元素。如果越界那行為將是未定義的。
float myY = myVec[1];
在矩陣中,可以通過一維的下標來獲得該列的向量(OpenGL的矩陣是列主順序的)。二維的小標來獲得向量中的元素。
mat3 myMat = mat3(1.0);
vec3 myVec = myMat[0]; //獲得第一列向量 1.0, 0.0, 0.0float f = myMat[0][0]; // 第一列的第一個向量。
控制流
迴圈
與C和C++相似,GLSL語言也提供了for, while, do/while的迴圈方式。使用continue跳入下一次迴圈,break結束迴圈。
for (l = 0; l < numLights; l++)
{if (!lightExists[l])continue;
color += light[l];
}while (i < num)
{
sum += color[i];
i++;
}do{
color += light[lightNum];
lightNum--;
}while (lightNum > 0)
if/else
color = unlitColor;if (numLights > 0)
{
color = litColor;
}else{
color = unlitColor;
}
discard
片段著色器中有一種特殊的控制流成為discard。使用discard會退出片段著色器,不執行後面的片段著色操作。片段也不會寫入幀緩衝區。
if (color.a < 0.9)
discard;
函式
在每個shader中必須有一個main函式。main函式中的void引數是可選的,但返回值是void時必須的。
voidmain(void){
...
}
GLSL中的函式,必須是在全域性範圍定義和宣告的。不能在函式定義中宣告或定義函式。函式必須有返回型別,引數是可選的。引數的修飾符(in, out, inout, const等)是可選的。
//函式宣告bool isAnyNegative(const vec4 v);//函式呼叫void main(void)
{bool isNegative = isAnyNegative(gl_Color);
...
}//定義bool isAnyNegative(const vec4 v)
{if (v.x < 0.0 || v.y < 0.0 || v.z < 0.0 || v.w < 0.0)return true;elsereturn false;
}
結構體和陣列也可以作為函式的引數。如果是陣列作為函式的引數,則必須制定其大小。在呼叫傳參時,只傳陣列名就可以了。
vec4 sumVectors(int sumSize, vec4 v[10]);voidmain(){
vec4 myColors[10];
...
vec4 sumColor = sumVectors(5, myColors);
}
vec4 sumVectors(int sumSize, vec4 v[10]){int i = 0;
vec4 sum = vec4(0.0);for(; i < sumSize; ++i)
{
sum += v[i];
}return sum;
}
GLSL的函式是支援過載的。函式可以同名但其引數型別或者引數個數不同即可。
floatsum(float a, float b){return a + b;
}
vec3 sum(vec3 v1, vec3 v2){return v1 + v2;
}
GLSL中函式遞迴是不被允許的。其行為是未定義的。
相關推薦
圖形處理之Shader語言(一)GLSL語法篇
變數 GLSL的變數命名方式與C語言類似。變數的名稱可以使用字母,數字以及下劃線,但變數名不能以數字開頭,還有變數名不能以gl_作為字首,這個是GLSL保留的字首,用於GLSL的內部變數。當然還有一些GLSL保留的名稱是不能夠作為變數的名稱的。 基本型別 除了布林型,整型
圖形處理之Shader語言(二)CG語法篇
Cg(C for Graphcis)語言,是NVIDIA與Microsoft合作研發,旨在為開發人員提供一套方便、跨平臺(良好的相容性),控制可程式設計圖形硬體的高階語言。 學習書籍 :GPU
影象處理之特徵提取(一)之HOG特徵 特徵數的計算
對於64128的影象而言,每88的畫素組成一個cell,每22個cell組成一個塊,也就是說,64128的圖片,總共有36715=3780個特徵。 單個cell的9個特徵,每個block(掃描視窗)包含22個cell也就是229=36個特徵,一個64128大小的
影象處理之特徵提取(一):HOG特徵
HOG方向梯度直方圖: (1)具體在HOG中方向梯度的實現:首先用[-1,0,1]梯度運算元對原影象做卷積運算,得到x方向(水平方向,以向右為正方向)的梯度分量gradscalx,然後用[1,0,-1]T梯度運算元對原影象做卷積運算,得到y方向(豎直方向,以向上為正方向)的
影象處理之特徵提取(一)之HOG特徵簡單梳理
上圖是一張行人圖的四種表示方式,原三色圖,灰度圖,邊緣圖,梯度圖,人腦根據前期學習與先驗知識很容易理解到影象中包含著一個行人,並可以根據一定情況將其從影象中摳選出來,但計算機是怎麼思考的呢?怎樣讓計算機理解以上影象中包含的是一個行人呢?前三個影象現在情況不適用,所以選取梯度圖,現在的梯度圖同樣也是人腦處理
影象處理之其他雜項(一)之MeanShift的目標跟蹤演算法opencv c++程式碼 VS2015+opencv3.2
//#include "stdafx.h" //#include "cv.h" //#include "highgui.h" #include<opencv.hpp> #define u_char unsigned char #define DIST 0.5 #define
圖形資料庫之Neo4j學習(一)
最近工作需要使用圖形資料庫來構建知識圖譜,目前基於Java使用最廣泛的有兩個開源框架 (1) neo4j 社群版 免費 企業版 收費 (2) Titan 全開源 我們此次選擇了neo4j的社群版,主要是專案緊,neo4j比較穩定,Titan可能比較新,雖然
FPGA影象處理之行快取(linebuffer)的設計一 FPGA影象處理之行快取(linebuffer)的設計一
轉載: FPGA影象處理之行快取(linebuffer)的設計一 FPGA影象處理之行快取(linebuffer)的設計一 作者:OpenS_Lee 1 背景知識 在FPGA數字影象處理中,行快取的使用非常頻繁,
linux學習筆記之shell程式設計(一)正則表示式與字元處理
shell程式設計 基礎正則表示式 正則和萬用字元的區別:正則是包含匹配,匹配檔案內容,grep,awk等支援正則表示式。萬用字元是完全匹配,匹配檔名,例如find,ls不認識正則表示式 ####正則表示式常用的字元(注意區別於萬用字元裡面的符號)#### -*
C語言學習入們到精通之學習筆記(一)
為什麼我通過部落格的形式與大家分享我的學習筆記 對於c語言的學習已經有快3年之久了,對於學習嵌入式的我看來,C是我們的根本也就是我們的核心知識點,想學習好嵌入式就必須精通C語言。在一年之前我對C語言的認識只停留在表面,只會用C語言寫寫51微控制器或STM32的控制程
C語言資料結構之稀疏矩陣(一)
最近開始學習C語言的稀疏矩陣的一些知識,現在簡單的整理梳理一下知識脈絡,僅供自己總結學習,歡迎技術指正,拒絕盲噴。 1.首先先介紹一下關於稀疏矩陣的一些基礎知識,關於稀疏矩陣,一直都沒有過很清楚詳細的定義。簡單的說,在M*N的一個矩陣中,假設有t個元素不為0,那麼有計算公
深度學習在自然語言處理中的應用(一)
資料整理篇 經典教材 Speech and Language Processing (第1,2版內容略陳舊,第三版很入時, 但有些重要章節沒放在網上) https://web.stanford.edu
Spring mvc請求處理流程詳解(一)之檢視解析
前言 Spring mvc框架相信很多人都很熟悉了,關於這方面的資料也是一搜一大把。但是感覺講的都不是很細緻,讓很多初學者都雲裡霧裡的。本人也是這樣,之前研究過,但是後面一段時間不用發現又忘記了。所以決定寫下來,以備後用。 本系列文基於spring-
C語言之網路程式設計(一)域名解析
在網路程式設計時,知道域名是不能直接訪問一個主機的,需要轉換成相應的IP地址。有時在程式中需要將一個IP地址轉換成一個域名。本節將講解C程式中的IP地址與域名的轉換問題。 提示:在TCP/IP網路中,通訊雙方的主機必須知道彼此的IP地址方可進行正常的通訊,如果給出的主機的域
R讀書筆記之特徵工程(一)空值處理
在特徵處理中,會有空值的刪除或者填充。 一:刪除 1一般刪除是最簡單的,用na.omit(data)就搞定,但是太粗暴了。 2若是有的觀測量空缺值太多的話,確實需要刪除,因為用別的方法填充反而會導致模型偏差。 那麼腫麼統計觀測量的空值的個數捏?可以參
基於C/C++語言資料結構之線性表(一)
資料結構學習筆記: 資料結構的重要性:資料結構我感覺很重要,不僅僅是考試很重要,而且在以後程式設計師事業上都是尤為重要的,知乎上有網友評價資料結構是最重要的程式設計基本能力,沒有之一。我感覺這個說法很對,並且大家都知道,資料結構與演算法這種說法常常被大家使用,就是因為資料
【Java開發手冊之異常日誌(一)】異常處理
【強制】不要捕獲 Java 類庫中定義的繼承自 RuntimeException 的執行時異常類,如: IndexOutOfBoundsException / NullPointerException,這類異常由程式設計師預檢查 來規避,保
設計模式之問題集錦(一)
是把 後繼 ogr data- 跟著 沒有 解釋器 space 基本實現 設計模式的主要資料是《大話設計模式》。第一階段先看看各種模式的基本概念。實現每一個模式下的樣例。然後在進行理解性的學習和掌握,靈活掌握各種模式的長處,知道某種模式適合那種狀態。如今,樣
MVC系列博客之排球計分(一)需求分析
height repl 系列 ges 優勢 針對 .... 9.png ota 項目簡介: 這是MVC系列博客之排球計分程序,該程序可以是對教練或者裁判使用的,讓教練有權限對隊員進行查詢得分情況,讓教練對隊員的優勢劣勢進行了解,以便對隊伍進行調整。 讓裁判更
android深入之設計模式(一)托付模式
-h listen back != new 聚合 string static data- (一)托付模式簡單介紹 托付模式是主要的設計模式之中的一個。托付。即是讓還有一個對象幫你做事情。 更多的模式,如狀態模式、策略模式、訪問者模式本質上是在更特殊的場合採用了托