學(xué)習(xí)WebGL之深入了解Shader

本系列所有文章目錄

本文將帶大家深入了解Shader畸肆,下面是運(yùn)行截圖尿贫,可以前往我的博客查看代碼演示拍柒。

前言

上篇文章中我們已經(jīng)和Shader有了一面之緣揭厚,本文將帶大家深入Shader的世界币砂,介紹Shader的語言特性尖飞,數(shù)據(jù)類型,內(nèi)置方法等等凌受。Shader語言和C語言很相似阵子,如果你學(xué)過C語言應(yīng)該可以很快適應(yīng)Shader的編程風(fēng)格。本文提供了一個具備Shader基本編程元素的例子胜蛉,通過Shader控制三角形旋轉(zhuǎn)挠进,并把位置轉(zhuǎn)變成了顏色,讀者可以通過修改這個例子更快的熟悉Shader誊册。

代碼框架

無論是Vertex Shader還是Fragment Shader领突,都有基本的代碼框架。下面是本文使用的Vertex Shader案怯。

attribute vec4 position;
varying vec4 fragColor;
uniform float elapsedTime;
void main() {
    fragColor = position * 0.5 + 0.5;
    float rotateAngle = elapsedTime * 0.001;
    float x = position.x * cos(rotateAngle) - position.y * sin(rotateAngle);
    float y = position.x * sin(rotateAngle) + position.y * cos(rotateAngle);
    gl_Position = vec4(x, y, 0.0, 1.0);
}

只有Vertex Shader可以聲明attribute變量君旦,它用來接受CPU傳遞過來的頂點數(shù)據(jù)。除了attribute變量之外嘲碱,還可以聲明uniform變量和varying變量金砍。具體含義還以下面會作詳解。main方法是Shader代碼執(zhí)行的入口麦锯,這和C語言一模一樣恕稠。在Vertex Shader中你必須給gl_Position賦值,否則這個Vertex Shader沒有任何意義扶欣,沒有任何頂點會傳遞給GPU鹅巍。

下面是本文使用的Fragment Shader。

varying mediump vec4 fragColor;
void main() {
    gl_FragColor = fragColor;
}

Fragment Shader除了attribute變量其他變量都可以擁有料祠,varying變量必須和Vertex Shader中的varying變量類型保持一致骆捧,varying變量會從Vertex Shader傳遞到Fragment Shader中。那么問題來了髓绽,Vertex Shader是每個頂點調(diào)用一次凑懂,而Fragment Shader是每個像素調(diào)用一次,那么頂點之間像素的varying變量值是如何計算的呢梧宫?答案是GPU會根據(jù)要繪制的形狀自動插值計算接谨。大家可以觀察示例,三角形頂點之間的顏色正是通過各個頂點的fragColor插值計算出來的塘匣。

變量類型

Shader有下面幾種變量類型:

  • void 和C語言的void一樣脓豪,無類型
  • bool 布爾
  • int 有符號的int
  • float 浮點數(shù)
  • vec2, vec3, vec4 2,3忌卤,4維向量扫夜,如果你不知道什么是向量,可以理解為2驰徊,3笤闯,4長度的數(shù)組。
  • bvec2, bvec3, bvec4 2棍厂,3颗味,4維布爾值的向量。
  • ivec2, ivec3, ivec4 2牺弹,3浦马,4維int值的向量。
  • mat2, mat3, mat4 2x2, 3x3, 4x4 浮點數(shù)的矩陣张漂,如果你不了解矩陣晶默,后面會有一篇文章單獨介紹矩陣。
  • sampler2D 紋理航攒,后面會詳細(xì)介紹磺陡。
  • samplerCube Cube紋理,后面會詳細(xì)介紹漠畜。

變量精度

細(xì)心的讀者可能會發(fā)現(xiàn)同樣是varying變量币他,在Fragment Shader中多了一個mediump修飾符。mediump表示的是變量類型的精度盆驹。因為Fragment Shader是逐像素執(zhí)行圆丹,所以會盡量控制計算的復(fù)雜度。對于不需要過高精度的變量躯喇,可以手動指定精度從而提高性能辫封。精度主要分為下面3種。

  • highp, 16bit廉丽,浮點數(shù)范圍(-2^62, 2^62)倦微,整數(shù)范圍(-2^16, 2^16)
  • mediump, 10bit,浮點數(shù)范圍(-2^14, 2^14)正压,整數(shù)范圍(-2^10, 2^10)
  • lowp, 8bit欣福,浮點數(shù)范圍(-2, 2),整數(shù)范圍(-2^8, 2^8)
    如果你想所有的float都是高精度的焦履,可以在Shader頂部聲明precision highp float;拓劝,這樣你就不需要為每一個變量聲明精度了雏逾。

運(yùn)算符

Shader可以使用所有C語言的運(yùn)算符。不過要注意的是二元運(yùn)算比如加法郑临,乘法等栖博,只能用在兩個類型相同的變量上,比如float只能和float相加厢洞。因為Shader不會為你進(jìn)行隱式的類型轉(zhuǎn)換仇让,這樣會增加GPU的負(fù)擔(dān)。我們表示float變量時躺翻,需要自行增加小數(shù)點丧叽,比如浮點數(shù)5要寫成5.0,否則會被認(rèn)定為整數(shù)公你。下面是能夠使用的運(yùn)算符踊淳,讀者可以當(dāng)做參考。


uniform變量

uniform變量會被所有Shader共享省店,比如有3個頂點嚣崭,Vertex Shader會被執(zhí)行3次,每次訪問的uniform變量都是同一個由js代碼設(shè)定好的值懦傍。下面是本文使用的設(shè)定uniform elapsedTime的js代碼雹舀。

  elapsedTimeUniformLoc = gl.getUniformLocation(program, 'elapsedTime');
  gl.uniform1f(elapsedTimeUniformLoc, elapesdTime);

首先獲取uniform elapsedTime在Shader中的位置,然后設(shè)置它的值粗俱。uniform1funiformXXX函數(shù)簇里面用來設(shè)置一個float類型uniform的方法说榆。通過uniformXXX里的XXX很容易看出來這個方法是設(shè)置什么類型的uniform的,下面是常見的幾種格式寸认。

  • uniform{n}{type} n表示數(shù)目1~4签财,type表示類型,floatf偏塞,inti唱蒸,unsigned intui。所以設(shè)置一個整數(shù)就是 uniform1i灸叼。
  • uniform{n}{type}v 相比于上面的多了一個v神汹,表示向量,所以傳遞的參數(shù)就是類型為type古今,維度為n的向量屁魏。
  • uniformMatrix{n}{type}v 這個用來設(shè)置類型為type nxn的矩陣。
    上面這些方法會在后面的文章中用到捉腥,這里大致了解即可氓拼。

varying變量

varying變量是Vertex Shader和Fragment Shader的橋梁,F(xiàn)ragment Shader中的varying變量由Vertex Shader中的varying變量自動插值計算出來。因為Fragment Shader是逐像素執(zhí)行桃漾,某些使用varying變量的效果在Fragment Shader中實現(xiàn)會更加細(xì)膩坏匪,比如光照效果。

向量的訪問

當(dāng)我們擁有一個vec4變量呈队,我們可以有很多種方法訪問它內(nèi)部的值剥槐。

  • vec4.x,vec4.y,vec4.z,vec4.w 通過x,y宪摧,z,w可以分別取出4個值颅崩。
  • vec4.xy,vec4.xx,vec4.xz,vec4.xyz 任意組合可以取出多種維度的向量几于。
  • vec4.r,vec4.g,vec4.b,vec4.a 還可以通過r,g沿后,b沿彭,a分別取出4個值,同上可以任意組合尖滚。
  • vec4.s,vec4.t,vec4.p,vec4.q 還可以通過s喉刘,t,p漆弄,q分別取出4個值睦裳,同上可以任意組合。
    vec3vec2也是同樣撼唾,無非就是少了幾個變量廉邑,比如vec3只有x,y倒谷,z蛛蒙。vec2只有x,y渤愁。

內(nèi)置方法

有很多內(nèi)置方法可以使用牵祟,如果可以選擇內(nèi)置方法實現(xiàn)算法,避免自己寫代碼再實現(xiàn)一遍抖格,因為內(nèi)置的方法能夠得到更好的硬件支持诺苹。下面是可用的方法表格。



可能很多方法你都不知道有什么用他挎,沒關(guān)系筝尾,后面使用到時我會再做解釋。

上面的介紹覆蓋了Shader的大部分基礎(chǔ)知識办桨,當(dāng)然還有很多使用細(xì)節(jié)和不常用的知識沒有介紹筹淫,這些知識會在后面使用到時再詳細(xì)介紹,這樣可以避免大家剛開始就對Shader產(chǎn)生畏懼感。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末损姜,一起剝皮案震驚了整個濱河市饰剥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌摧阅,老刑警劉巖汰蓉,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異棒卷,居然都是意外死亡顾孽,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門比规,熙熙樓的掌柜王于貴愁眉苦臉地迎上來若厚,“玉大人,你說我怎么就攤上這事蜒什〔饨眨” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵灾常,是天一觀的道長霎冯。 經(jīng)常有香客問我,道長钞瀑,這世上最難降的妖魔是什么沈撞? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮仔戈,結(jié)果婚禮上关串,老公的妹妹穿的比我還像新娘。我一直安慰自己监徘,他們只是感情好晋修,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著凰盔,像睡著了一般墓卦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上户敬,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天落剪,我揣著相機(jī)與錄音,去河邊找鬼尿庐。 笑死忠怖,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的抄瑟。 我是一名探鬼主播凡泣,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了鞋拟?” 一聲冷哼從身側(cè)響起骂维,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贺纲,沒想到半個月后航闺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡猴誊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年潦刃,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片稠肘。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡福铅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出项阴,到底是詐尸還是另有隱情,我是刑警寧澤笆包,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布环揽,位于F島的核電站,受9級特大地震影響庵佣,放射性物質(zhì)發(fā)生泄漏歉胶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一巴粪、第九天 我趴在偏房一處隱蔽的房頂上張望通今。 院中可真熱鬧,春花似錦肛根、人聲如沸辫塌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽臼氨。三九已至,卻和暖如春芭届,著一層夾襖步出監(jiān)牢的瞬間储矩,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工褂乍, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留持隧,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓逃片,卻偏偏與公主長得像屡拨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

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