《OpenGL ES: (四)著色器語言》

關(guān)于著色器

著色器是用來實現(xiàn)圖像渲染的灭必,用來替代固定渲染管線的可編程程序。著色器替代了傳統(tǒng)的固定渲染管線埃唯,可以實現(xiàn)3D圖形學計算中的相關(guān)計算析蝴,由于其可編程性矗钟,可以實現(xiàn)各種各樣的圖像效果而不用受顯卡的固定渲染管線限制。這極大的提高了圖像的畫質(zhì)嫌变。

本篇博客重點介紹GLSL語言本身吨艇,關(guān)于固定管道和可編程管道的介紹可自行查閱,或者直接參照Android OpenGLES2.0(一)——了解OpenGLES2.0的OpenGLES1.x和OpenGLES2.0的渲染管道圖腾啥,即可知道固定渲染管道和可編程渲染管道的區(qū)別东涡。
關(guān)于著色器前面的博客也提到過,在OpenGLES中著色器分為頂點著色器和片元著色器倘待,我們可以理解為:頂點著色器是針對每個頂點執(zhí)行一次疮跑,用于確定頂點的位置;片元著色器是針對每個片元(可以理解為每個像素)執(zhí)行一次凸舵,用于確定每個片元(像素)的顏色祖娘。

著色器語言簡介

OpenGLES的著色器語言GLSL是一種高級的圖形化編程語言,其源自應用廣泛的C語言啊奄。與傳統(tǒng)的C語言不同的是渐苏,它提供了更加豐富的針對于圖像處理的原生類型,諸如向量菇夸、矩陣之類琼富。OpenGLES 主要包含以下特性:

  • GLSL是一種面向過程的語言,和Java的面向?qū)ο笫遣煌摹?/li>
  • GLSL的基本語法與C/C++基本相同庄新。
  • 它完美的支持向量和矩陣操作鞠眉。
  • 它是通過限定符操作來管理輸入輸出類型的。
  • GLSL提供了大量的內(nèi)置函數(shù)來提供豐富的擴展功能择诈。

在前面的博客示例中械蹋,我們所使用的都是非常簡單的著色器,基本沒有使用過GLSL的內(nèi)置函數(shù)羞芍,在后面使用光照哗戈、貼圖等等其他功能,我們不可避免的要使用這些內(nèi)置函數(shù)涩金。

著色器語言基礎(chǔ)

GLSL雖然是基于C/C++的語言谱醇,但是它和C/C++還是有很大的不同的,比如在GLSL中沒有double步做、long等類型副渴,沒有unionenum全度、unsigned以及位運算等特性煮剧。

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

GLSL中的數(shù)據(jù)類型主要分為標量、向量、矩陣勉盅、采樣器佑颇、結(jié)構(gòu)體、數(shù)組草娜、空類型七種類型:

  • 標量:標量表示的是只有大小沒有方向的量挑胸,在GLSL中標量只有bool、int和float三種宰闰。對于int茬贵,和C一樣,可以寫為十進制(16)移袍、八進制(020)或者十六進制(0x10)解藻。關(guān)于進制不了解的,得自己補補葡盗,這是編程基礎(chǔ)螟左。對于標量的運算,我們最需要注意的是精度觅够,防止溢出問題胶背。

  • 向量:向量我們可以看做是數(shù)組,在GLSL通常用于儲存顏色蔚约、坐標等數(shù)據(jù)奄妨,針對維數(shù)涂籽,可分為二維苹祟、三維和四位向量。針對存儲的標量類型评雌,可以分為bool树枫、int和float。共有vec2景东、vec3砂轻、vec4,ivec2斤吐、ivec3搔涝、ivec4、bvec2和措、bvec3和bvec4九種類型庄呈,數(shù)組代表維數(shù)、i表示int類型派阱、b表示bool類型诬留。需要注意的是,GLSL中的向量表示豎向量,所以與矩陣相乘進行變換時文兑,矩陣在前盒刚,向量在后(與DirectX正好相反)。向量在GPU中由硬件支持運算绿贞,比CPU快的多因块。

    1. 作為顏色向量時,用rgba表示分量籍铁,就如同取數(shù)組的中具體數(shù)據(jù)的索引值贮聂。三維顏色向量就用rgb表示分量。比如對于顏色向量vec4 color寨辩,color[0]和color.r都表示color向量的第一個值吓懈,也就是紅色的分量。其他相同靡狞。
    2. 作為位置向量時耻警,用xyzw表示分量,xyz分別表示xyz坐標甸怕,w表示向量的模甘穿。三維坐標向量為xyz表示分量,二維向量為xy表示分量梢杭。
    3. 作為紋理向量時温兼,用stpq表示分量,三維用stp表示分量武契,二維用st表示分量募判。
  • 矩陣:在GLSL中矩陣擁有22、33咒唆、4*4三種類型的矩陣届垫,分別用mat2、mat3全释、mat4表示装处。我們可以把矩陣看做是一個二維數(shù)組,也可以用二維數(shù)組下表的方式取里面具體位置的值浸船。

  • 采樣器:采樣器是專門用來對紋理進行采樣工作的妄迁,在GLSL中一般來說,一個采樣器變量表示一副或者一套紋理貼圖李命。所謂的紋理貼圖可以理解為我們看到的物體上的皮膚登淘。

  • 結(jié)構(gòu)體:和C語言中的結(jié)構(gòu)體相同,用struct來定義結(jié)構(gòu)體项戴,關(guān)于結(jié)構(gòu)體參考C語言中的結(jié)構(gòu)體形帮。

  • 數(shù)組:數(shù)組知識也和C中相同槽惫,不同的是數(shù)組聲明時可以不指定大小,但是建議在不必要的情況下辩撑,還是指定大小的好界斜。

  • 空類型:空類型用void表示,僅用來聲明不返回任何值得函數(shù)合冀。

變量聲明示例:

float a=1.0;
int b=1;
bool c=true;
vec2 d=vec2(1.0,2.0);
vec3 e=vec3(1.0,2.0,3.0)
vec4 f=vec4(vec3,1.2);
vec4 g=vec4(0.2);  //相當于vec(0.2,0.2,0.2,0.2)
vec4 h=vec4(a,a,1.3,a);
mat2 i=mat2(0.1,0.5,1.2,2.4);
mat2 j=mat2(0.8);   //相當于mat2(0.8,0.8,0.8,0.8)
mat3 k=mat3(e,e,1.2,1.6,1.8);

運算符

GLSL中的運算符有(越靠前各薇,運算優(yōu)先級越高):
1. 索引:[]
2. 前綴自加和自減:++,–
3. 一元非和邏輯非:~君躺,峭判!
4. 加法和減法:+,-
5. 等于和不等于:==棕叫,林螃!=
6. 邏輯異或:^^
7. 三元運算符號,選擇:俺泣?:
8. 成員選擇與混合:.
9. 后綴自加和自減:++疗认,–
10. 乘法和除法:,/
11. 關(guān)系運算符:>伏钠,<横漏,=,>=熟掂,<=缎浇,<>
12. 邏輯與:&&
13. 邏輯或:||
14. 賦值預算:=,+=赴肚,-=素跺,
=,/=

類型轉(zhuǎn)換

GLSL的類型轉(zhuǎn)換與C不同尊蚁。在GLSL中類型不可以自動提升亡笑,比如float a=1;就是一種錯誤的寫法,必須嚴格的寫成float a=1.0横朋,也不可以強制轉(zhuǎn)換,即float a=(float)1;也是錯誤的寫法百拓,但是可以用內(nèi)置函數(shù)來進行轉(zhuǎn)換琴锭,如float a=float(1);還有float a=float(true);(true為1.0,false為0.0)等衙传,值得注意的是决帖,低精度的int不能轉(zhuǎn)換為低精度的float。蓖捶。

限定符

在之前的博客中也提到了地回,GLSL中的限定符號主要有:

  • attritude:一般用于各個頂點各不相同的量。如頂點顏色、坐標等刻像。
  • uniform:一般用于對于3D物體中所有頂點都相同的量畅买。比如光源位置,統(tǒng)一變換矩陣等细睡。
  • varying:表示易變量谷羞,一般用于頂點著色器傳遞到片元著色器的量。
  • const:常量溜徙。

限定符與java限定符類似浓恳,放在變量類型之前更米,并且只能用于全局變量。在GLSL中,沒有默認限定符一說人乓。

流程控制

GLSL中的流程控制與C中基本相同,主要有:

  • if(){}驰弄、if(){}else{}云石、if(){}else if(){}else{}
  • while(){}和do{}while()
  • for(;;){}
  • break和continue

函數(shù)

GLSL中也可以定義函數(shù),定義函數(shù)的方式也與C語言基本相同求妹。函數(shù)的返回值可以是GLSL中的除了采樣器的任意類型乏盐。對于GLSL中函數(shù)的參數(shù),可以用參數(shù)用途修飾符來進行修飾制恍,常用修飾符如下:

  • in:輸入?yún)?shù)父能,無修飾符時默認為此修飾符。
  • out:輸出參數(shù)净神。
  • inout:既可以作為輸入?yún)?shù)何吝,又可以作為輸出參數(shù)。

浮點精度

與頂點著色器不同的是鹃唯,在片元著色器中使用浮點型時爱榕,必須指定浮點類型的精度,否則編譯會報錯坡慌。精度有三種黔酥,分別為:

  • lowp:低精度。8位洪橘。
  • mediump:中精度跪者。10位。
  • highp:高精度熄求。16位渣玲。

具體如下表:

image.png

不僅僅是float可以制定精度,其他(除了bool相關(guān))類型也同樣可以弟晚,但是int忘衍、采樣器類型并不一定要求指定精度逾苫。加精度的定義如下:

uniform lowp float a=1.0;
varying mediump vec4 c;

當然,也可以在片元著色器中設置默認精度枚钓,只需要在片元著色器最上面加上precision <精度> <類型>即可制定某種類型的默認精度铅搓。其他情況相同的話,精度越高秘噪,畫質(zhì)越好狸吞,使用的資源也越多。

程序結(jié)構(gòu)

前面幾篇博客都有使用到著色器指煎,我們對著色器的程序結(jié)構(gòu)也應該有一定的了解蹋偏。也許一直沉浸在Android應用開發(fā),沒有了解C開發(fā)的朋友至壤,對這種結(jié)構(gòu)并不熟悉威始。GLSL程序的結(jié)構(gòu)和C語言差不多,main()方法表示入口函數(shù)像街,可以在其上定義函數(shù)和變量黎棠,在main中可以引用這些變量和函數(shù)。定義在函數(shù)體以外的叫做全局變量镰绎,定義在函數(shù)體內(nèi)的叫做局部變量脓斩。與高級語言不通的是,變量和函數(shù)在使用前必須聲明畴栖,不能再使用的后面聲明變量或者函數(shù)随静。

內(nèi)建變量

在著色器中我們一般都會聲明變量來在程序中使用,但是著色器中還有一些特殊的變量吗讶,不聲明也可以使用燎猛。這些變量叫做內(nèi)建變量。內(nèi)建變量照皆,相當于著色器硬件的輸入和輸出點重绷,使用者利用這些輸入點輸入之后,就會看到屏幕上的輸出膜毁。通過輸出點可以知道輸出的某些數(shù)據(jù)內(nèi)容昭卓。當然,實際上肯定不會這樣簡單爽茴,這么說只是為了幫助理解葬凳。在頂點著色器中的內(nèi)建變量和片元著色器的內(nèi)建變量是不相同的。著色器中的內(nèi)建變量有很多室奏,在此,我們只列出最常用的集中內(nèi)建變量劲装。

頂點著色器的內(nèi)建變量

  1. 輸入變量:

    • gl_Position:頂點坐標
    • gl_PointSize:點的大小胧沫,沒有賦值則為默認值1昌简,通常設置繪圖為點繪制才有意義。

片元著色器的內(nèi)建變量

  1. 輸入變量

    • gl_FragCoord:當前片元相對窗口位置所處的坐標绒怨。
    • gl_FragFacing:bool型纯赎,表示是否為屬于光柵化生成此片元的對應圖元的正面。
  2. 輸出變量

    • gl_FragColor:當前片元顏色
    • gl_FragData:vec4類型的數(shù)組南蹂。向其寫入的信息犬金,供渲染管線的后繼過程使用。

常用內(nèi)置函數(shù)

常見函數(shù)

  • radians(x):角度轉(zhuǎn)弧度
  • degrees(x):弧度轉(zhuǎn)角度
  • sin(x):正弦函數(shù)六剥,傳入值為弧度晚顷。相同的還有cos余弦函數(shù)、tan正切函數(shù)疗疟、asin反正弦该默、acos反余弦、atan反正切
  • pow(x,y):
  • exp(x):
  • exp2(x):2的x次方
  • log(x):
  • log2(x):
  • sqrt(x):對x開根號
  • inversesqr(x):
  • abs(x):取x的絕對值
  • sign(x):x>0返回1.0策彤,x<0返回-1.0栓袖,否則返回0.0
  • ceil(x):返回大于或者等于x的整數(shù)
  • floor(x):返回小于或者等于x的整數(shù)
  • fract(x):返回x-floor(x)的值
  • mod(x,y):取模(求余)
  • min(x,y):獲取xy中小的那個
  • max(x,y):獲取xy中大的那個
  • mix(x,y,a):返回<nobr aria-hidden="true">x?(1?a)+y?a
  • step(x,a):x< a返回0.0,否則返回1.0
  • smoothstep(x,y,a):a < x返回0.0店诗,a>y返回1.0裹刮,否則返回0.0-1.0之間平滑的Hermite插值。
  • dFdx(p):p在x方向上的偏導數(shù)
  • dFdy(p):p在y方向上的偏導數(shù)
  • fwidth(p):p在x和y方向上的偏導數(shù)的絕對值之和

幾何函數(shù)

  • length(x):計算向量x的長度
  • distance(x,y):返回向量xy之間的距離
  • dot(x,y):返回向量xy的點積
  • cross(x,y):返回向量xy的差積
  • normalize(x):返回與x向量方向相同庞瘸,長度為1的向量

矩陣函數(shù)

  • matrixCompMult(x,y):將矩陣相乘
  • lessThan(x,y):返回向量xy的各個分量執(zhí)行x< y的結(jié)果捧弃,類似的有g(shù)reaterThan,equal,notEqual
  • lessThanEqual(x,y):返回向量xy的各個分量執(zhí)行x<= y的結(jié)果,類似的有類似的有g(shù)reaterThanEqual
  • any(bvec x):x有一個元素為true恕洲,則為true
  • all(bvec x):x所有元素為true塔橡,則返回true,否則返回false
  • not(bvec x):x所有分量執(zhí)行邏輯非運算

紋理采樣函數(shù)

紋理采樣函數(shù)有texture2D霜第、texture2DProj葛家、texture2DLod、texture2DProjLod泌类、textureCube癞谒、textureCubeLod及texture3D、texture3DProj刃榨、texture3DLod弹砚、texture3DProjLod等。

  • texture表示紋理采樣枢希,2D表示對2D紋理采樣桌吃,3D表示對3D紋理采樣
  • Lod后綴,只適用于頂點著色器采樣
  • Proj表示紋理坐標st會除以q

紋理采樣函數(shù)中苞轿,3D在OpenGLES2.0并不是絕對支持茅诱。我們再次暫時不管3D紋理采樣函數(shù)逗物。重點只對texture2D函數(shù)進行說明。texture2D擁有三個參數(shù)瑟俭,第一個參數(shù)表示紋理采樣器翎卓。第二個參數(shù)表示紋理坐標,可以是二維摆寄、三維失暴、或者四維。第三個參數(shù)加入后只能在片元著色器中調(diào)用微饥,且只對采樣器為mipmap類型紋理時有效逗扒。

小結(jié)

到這里,關(guān)于著色器語言GLSL就大致介紹完了畜号,相對Java來說缴阎,GLSL語言不知簡單了多少倍。結(jié)合之前博客的案例简软,相信我們也能夠?qū)懸恍┖唵蔚闹髁寺巍T诤罄m(xù)的博客中,我們將會學習紋理痹升、光照建炫、混合與霧、圖像處理等內(nèi)容疼蛾,將會頻繁的用到著色器語言肛跌,在使用的過程中,我們才能更好的掌握GLSL察郁。
轉(zhuǎn):https://blog.csdn.net/junzia/article/details/52830604

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末衍慎,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子皮钠,更是在濱河造成了極大的恐慌稳捆,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,835評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件麦轰,死亡現(xiàn)場離奇詭異乔夯,居然都是意外死亡,警方通過查閱死者的電腦和手機款侵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,900評論 2 383
  • 文/潘曉璐 我一進店門末荐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人新锈,你說我怎么就攤上這事甲脏。” “怎么了?”我有些...
    開封第一講書人閱讀 156,481評論 0 345
  • 文/不壞的土叔 我叫張陵剃幌,是天一觀的道長聋涨。 經(jīng)常有香客問我晾浴,道長负乡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,303評論 1 282
  • 正文 為了忘掉前任脊凰,我火速辦了婚禮抖棘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘狸涌。我一直安慰自己切省,他們只是感情好,可當我...
    茶點故事閱讀 65,375評論 5 384
  • 文/花漫 我一把揭開白布帕胆。 她就那樣靜靜地躺著朝捆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪懒豹。 梳的紋絲不亂的頭發(fā)上芙盘,一...
    開封第一講書人閱讀 49,729評論 1 289
  • 那天,我揣著相機與錄音脸秽,去河邊找鬼儒老。 笑死,一個胖子當著我的面吹牛记餐,可吹牛的內(nèi)容都是我干的驮樊。 我是一名探鬼主播,決...
    沈念sama閱讀 38,877評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼片酝,長吁一口氣:“原來是場噩夢啊……” “哼囚衔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起雕沿,我...
    開封第一講書人閱讀 37,633評論 0 266
  • 序言:老撾萬榮一對情侶失蹤练湿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后晦炊,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鞠鲜,經(jīng)...
    沈念sama閱讀 44,088評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,443評論 2 326
  • 正文 我和宋清朗相戀三年断国,在試婚紗的時候發(fā)現(xiàn)自己被綠了贤姆。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,563評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡稳衬,死狀恐怖霞捡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情薄疚,我是刑警寧澤碧信,帶...
    沈念sama閱讀 34,251評論 4 328
  • 正文 年R本政府宣布赊琳,位于F島的核電站,受9級特大地震影響砰碴,放射性物質(zhì)發(fā)生泄漏躏筏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,827評論 3 312
  • 文/蒙蒙 一呈枉、第九天 我趴在偏房一處隱蔽的房頂上張望趁尼。 院中可真熱鬧,春花似錦猖辫、人聲如沸酥泞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,712評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芝囤。三九已至,卻和暖如春悯姊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背挠轴。 一陣腳步聲響...
    開封第一講書人閱讀 31,943評論 1 264
  • 我被黑心中介騙來泰國打工耳幢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留岸晦,地道東北人。 一個月前我還...
    沈念sama閱讀 46,240評論 2 360
  • 正文 我出身青樓睛藻,卻偏偏與公主長得像,于是被迫代替她去往敵國和親店印。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,435評論 2 348

推薦閱讀更多精彩內(nèi)容