1. 程式人生 > >圖形處理之Shader語言(一)GLSL語法篇

圖形處理之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.01.02.01.0};
myColor.x = -1.0;
myColor.yz = vec2(3.05.0);
myColor.wx = vec2(1.03.0);
myColor.zz = vec2(2.03.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- (一)托付模式簡單介紹 托付模式是主要的設計模式之中的一個。托付。即是讓還有一個對象幫你做事情。 更多的模式,如狀態模式、策略模式、訪問者模式本質上是在更特殊的場合採用了托