OpenGL編程語言-glsl基礎(chǔ)

前言

作為一個開發(fā)者,有一個學(xué)習(xí)的氛圍跟一個交流圈子特別重要這是一個我的iOS交流群:776598941,不管你是小白還是大牛歡迎入駐 ,分享BAT,阿里面試題、面試經(jīng)驗,討論技術(shù), 大家一起交流學(xué)習(xí)成長!

最近在研究OpenGL 被各種陌生的名詞虐成狗,所以記錄下來一些學(xué)習(xí)知識點供學(xué)習(xí)和參考.

GLSL是什么?

GLSL(OpenGL Shading Language) 是OpenGL的著色器語言,純粹的和GPU打交道的計算機(jī)語言.可以理解為C的變種專門針對OpenGL編程,不支持指針等等一些C的特性等. (名詞解釋:著色器(Shader))

GPU是多線程并行處理器,GLSL直接面向單指令流多數(shù)據(jù)流(SIMD)模型的多線程計算。

GLSL編寫的著色器函數(shù)是對每個數(shù)據(jù)同時執(zhí)行的。

每個頂點都會由頂點著色器中的算法處理,每個像素也都會由?片段著色器(也有叫片元著色器)中的算法處理。

初學(xué)者在編寫自己的著色器時,需要考慮到SIMD的并發(fā)特性,并用并行計算的思路來思考問題 這就是GLSL.

我們最常見的用法是在?頂點著色器里生成所需要的值,然后傳給?片斷著色器用.

GLSL能做什么

日以逼真的材質(zhì) – 金屬,巖石,木頭,油漆等

日益逼真的光照效果 – 區(qū)域光和軟陰影

非現(xiàn)實材質(zhì) – 美術(shù)效果,鋼筆畫,水墨畫和對插畫技術(shù)的模擬

針對紋理內(nèi)存的新用途

更少的紋理訪問

圖形處理 – 選擇,邊緣鈍化遮蔽和復(fù)雜混合

動畫效果 – 關(guān)鍵幀插值,粒子系統(tǒng)

用戶可編程的反走樣方法

GLSL注意

GLSL支持函數(shù)重載(就是父類定義方法,子類復(fù)寫該方法叫重載)

GLSL不存在數(shù)據(jù)類型的自動提升(就是不支持類型自動向上轉(zhuǎn)換 eg:float 轉(zhuǎn) double),類型必須嚴(yán)格保持一致.

GLSL不支持指針,字符串,字符,它基本上是一種處理數(shù)字?jǐn)?shù)據(jù)的語言

GLSL不支持聯(lián)合(union)、枚舉類型(enum)、結(jié)構(gòu)體(stuct)位字段(>> or << 左右移)及按位運算符(| or &這種按位與)(就是干掉麻煩的C操作 讓這個更單純的處理圖形數(shù)據(jù)使用)

GLSL的數(shù)據(jù)類型

GLSL有三種基本數(shù)據(jù)類型:

float

int

double

由float、int、double組成的array[]或者結(jié)構(gòu)體

42// 十進(jìn)制?

042// 八進(jìn)制?

0x2A// 十六進(jìn)制

注意:GLSL不支持指針,GLSL把向量和矩陣作為基本數(shù)據(jù)類型

向量(vector):有起始位置有方向的線段,也稱作?矢量(不要被這些名詞嚇到,我記得這個向量是我高二的時候數(shù)學(xué)學(xué)的東西).

矢量

矢量可以和標(biāo)量甚至矩陣做加減乘除(必須遵守一定規(guī)則才可以 否則報錯)

vec2,? vec3,? vec4? //包含2/3/4個浮點數(shù)的矢量(浮點型)

ivec2, ivec3, ivec4 //包含2/3/4個整數(shù)的矢量(整形數(shù) 前邊帶i 代表integer)

bvec2, bvec3, bvec4 //包含2/3/4個布爾值的矢量(bool不用解釋)

上邊這些是一種GLSL的數(shù)據(jù)類型, 可以簡單理解為?vec+數(shù)字?就代表 是一個數(shù)組里面放幾個元素(應(yīng)該都是 vec2~vec4之間,沒見過 vec5以上和vec2以下,好像這就代表幾維坐標(biāo)系),默認(rèn)元素是float浮點類型,前邊帶i代表integer整形,b代表bool.

vec如何聲明使用?

vec3 v; //聲明三維浮點型向量v

v[1] = 3.0;? //給向量v的第二個元素賦值(數(shù)組從0開始,下標(biāo)為1就是第二個元素)

//下面兩種等價

vec3 v = vec3(0.6); //數(shù)組是連續(xù)的存儲空間 相當(dāng)于其它元素默認(rèn)被這個0.6值填充

vec3 v = vec3(0.6,0.6,0.6);

注意: 除了用索引方式外,還能用選擇運算符的方式來使用向量.擇運算符是對于向量的各個元素(最多為4個)約定俗成的名稱,用一個小寫拉丁字母來表示。根據(jù)向量表示對象的意義不同,可以使用以下選擇運算符:

表示頂點可以用 (x、y、z、w) (坐標(biāo)系)

表示顏色可以用 (r、g、b、a) (顏色值帶透明)

表示紋理坐標(biāo)用 (s、t、p、q)

三種任選一種都一樣,作用都是等效的. 也就是說,如果v是一個向量,那么:

v[0]

v.x

v.r

v.s

都指的是向量v的第一個元素。

例如:

//用構(gòu)造函數(shù)的方式聲明并初始化四維浮點型

vec4v1 =vec4(1.0,2.0,3.0,4.0);

vec4v2;

v2.xy=v1.yz;//將v1的第二個和第三個元素復(fù)制到v2的第一個和第二個元素

v2.z=2.0;//給v2的第三個元素賦值?

v2.xy=v1.yx;//將v1的頭兩個元素互換,再復(fù)制到v2的頭兩個元素中

矩陣(matrix)

矩陣(matrix)以下類型都以mat開頭

mat2?代表2x2的矩陣

mat3?代表3x3的矩陣

mat4?代表4x4的矩陣

注意:矩陣是按列順序組織的,先列后行

如下代碼:

mat4m;//聲明四維浮點型方陣m?

m[2][3]=2.0;//給方陣的第三列、第四行元素賦值

// 下面兩種等價,初始化矩陣對角

mat2m =mat2(1.0)

mat2m =mat2(1.0,0.0,0.0,1.0);

取樣器(Sampler)

紋理查找需要制定哪個紋理或者紋理單元將制定查找.

sampler1D// 訪問一個一維紋理

sampler2D// 訪問一個二維紋理? ? ? ? ?

sampler3D// 訪問一個三維紋理

samplerCube// 訪問一個立方貼圖紋理

sampler1DShadow// 訪問一個帶對比的一維深度紋理

sampler2DShadow// 訪問一個帶對比的二維深度紋理

uniformsampler2Dgrass;

vcc2 coord =vec2(100,100);

vec4color =texture2D(grass, coord);

如果一個著色器在程序里結(jié)合多個文理, 可以使用取樣器數(shù)組.

constinttex_nums =4;

uniformsampler2Dtextures[tex_nums];

for(inti =0; i < tex_nums; ++i) {

sampler2Dtex = textures[i];

// todo ...

}

結(jié)構(gòu)體

這是唯一的用戶能用的自定義類型

struct light?

{?

vec3position;

vec3color;

};?

light ceiling_light;

數(shù)組

數(shù)組索引是從0開始的,而且沒有指針概念

// 創(chuàng)建一個10個元素的數(shù)組?

vec4points[10];

// 創(chuàng)建一個不指定大小的數(shù)組

vec4points[];

points[2] =vec4(1.0);// points現(xiàn)在大小為3

points[7] =vec4(2.0);// points現(xiàn)在大小為8

void

只能用于聲明函數(shù)返回值

類型轉(zhuǎn)換

必須明確地進(jìn)行類型轉(zhuǎn)換,不會自動類型提升

floatf =2.3;

boolb =bool(f);// b is true

限定符

GLSL中有4個限定符(variable qualifiers)可供使用,它們限定了被標(biāo)記的變量不能被更改的”范圍”.

const

attribute

uniform

varying

const: 和C++里差不多,定義不可變常量

表示限定的變量在編譯時不可被修改.

attribute:是應(yīng)用程序傳給頂點著色器用的

不允許聲明時初始化

attribute限定符標(biāo)記的是一種全局變量,該變量在頂點著色器中是只讀(read-only)的,該變量被用作從OpenGL應(yīng)用程序向頂點著色器中傳遞參數(shù),因此該限定符僅能用于頂點著色器.

attribute變量是只能在vertex shader中使用的變量

它不能在fragment shader中聲明attribute變量,

也不能被fragment shader中使用)

在application中,一般用函數(shù)glBindAttribLocation()來綁定每個attribute變量的位置,然后用函數(shù)

glVertexAttribPointer()為每個attribute變量賦值。

以下是例子:

uniform mat4 u_matViewProjection;

attribute vec4 a_position;

attribute vec2 a_texCoord0;

varying vec2 v_texCoord;

void main(void)

{

? gl_Position = u_matViewProjection * a_position;

? v_texCoord = a_texCoord0;

}

uniform:一般是應(yīng)用程序用于設(shè)定頂點著色器和片斷著色器相關(guān)初始化值.不允許聲明時初始化.uniform限定符標(biāo)記的是一種全局變量,該變量對于一個圖元(primitive)來說是不可更改的 它可以從OpenGL應(yīng)用程序中接收傳遞來的參數(shù)

uniform變量 外部程序傳遞給shader的變量.

函數(shù)glUniform**()函數(shù)賦值的.

shader 中是只讀變量,不能被 shader 修改.

uniform變量一般用來表示:變換矩陣,材質(zhì),光照參數(shù)和顏色等信息。

uniform mat4 viewProjMatrix; //投影+視圖矩陣

uniform mat4 viewMatrix;? ? ? ? //視圖矩陣

uniform vec3 lightPosition;? ? //光源位置

varying:用于傳遞頂點著色器的值給片斷著色器.它提供了從頂點著色器向片段著色器傳遞數(shù)據(jù)的方法,varying限定符可以在頂點著色器中定義變量,然后再傳遞給光柵化器,光柵化器對數(shù)據(jù)插值后,再將每個片段的值交給片段著色器.

varying變量是vertex和fragment shader之間做數(shù)據(jù)傳遞用的。

一般vertex shader修改varying變量的值,

然后fragment shader使用該varying變量的值。

因此varying變量在vertex和fragment shader二者之間的聲

明必須是一致的。

application不能使用此變量。

以下是例子:

// Vertex shaderuniform

mat4 u_matViewProjection;

attribute vec4 a_position;

attribute vec2 a_texCoord0;

varying vec2 v_texCoord; // Varying in vertex shader

void main(void)

{?

? gl_Position = u_matViewProjection * a_position;

? v_texCoord = a_texCoord0;

}

// Fragment shaderprecision

mediump float;

varying vec2 v_texCoord; // Varying in fragment shader

uniform sampler2D s_baseMap;

uniform sampler2D s_lightMap;

void main()

{

? vec4 baseColor;

? vec4 lightColor;

? baseColor = texture2D(s_baseMap, v_texCoord);

? lightColor = texture2D(s_lightMap, v_texCoord);

? gl_FragColor = baseColor * (lightColor + 0.25);

}

注意:以上這幾種限定符很重要

限制性

不能在if-else中聲明變量

用于判斷的條件必須是bool類型(if,while,for…)

(?:)操作符后兩個參數(shù)必須類型相同

不支持switch語句

vec4toonify(infloatintensify)

{

vec4color;

color =vec4(0.8,0.8,0.8,0.8)

returncolor;

}

discard

discard關(guān)鍵字可以避免片段更新幀緩沖區(qū),當(dāng)流控制遇到這個關(guān)鍵字時,正在處理的片段就會被標(biāo)記為丟.

如果不理解什么叫標(biāo)記為丟 可以參考一下UIView的繪制過程

函數(shù)

函數(shù)名可以通過參數(shù)類型重載,但是和返回值類型無關(guān)

所有參數(shù)必須完全匹配,參數(shù)不會自動

函數(shù)不能被遞歸調(diào)用

函數(shù)返回值不能是數(shù)組

函數(shù)參數(shù)標(biāo)識符

in: 進(jìn)復(fù)制到函數(shù)中,但不返回的參數(shù)(默認(rèn))

out: 不將參數(shù)復(fù)制到函數(shù)中,但返回參數(shù)

inout: 復(fù)制到函數(shù)中并返回

混合操作

通過在選擇器(.)后列出各分量名,就可以選擇這些分量

vec4v4;

v4.rgba;// 得到vec4

v4.rgb;// 得到vec3

v4.b;// 得到float

v4.xy;// 得到vec2

v4.xgba;// 錯誤!分量名不是同一類

v4.wxyz;// 打亂原有分量順序

v4.xxyy;// 重復(fù)分量

最后推薦一個GLSL編輯調(diào)試工具OpenGL Shader Builder(Graphics Tools.dmg)

文章來源于網(wǎng)絡(luò),如有侵權(quán),請聯(lián)系小編刪除!

全文完

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容