目錄
一、說明
二、著色器的變量
2.1 著色器變量
2.2 著色器內置變量
三、最常見內置變量使用范例
3.1 常見著色器變量
3.2 示例1: gl_PointSize?
3.3 示例2:gl_Position?
3.4 gl_FragColor
3.5 渲染點片元坐標gl_PointCoord
3.6 gl_PointCoord應用案例
四、GPU的內置函數
4. 1 內置函數列表
4.2 角度與三角函數
4.3 指數函數
4.4 通用函數
4.5 幾何函數
4.6 矩陣函數
4.7 矢量函數
4.8 紋理查詢函數
一、說明
????????著色器的內置變量和內置函數很有必要說一說,因為,初入門的時候不知道著色器有多深的水準,必須將它所蘊涵的東西統統擺到桌面上,才能有所準備,有所認知,有所實用。本篇就是將著色器默認的變量函數統統擺出,混個臉熟。
二、著色器的變量
2.1 著色器變量
????????著色器有兩種變量:
- 普通變量,著色器語言和C語言類似,需要先聲明后使用。
- 內置變量,所謂內置變量就是不用聲明可以直接賦值,主要是為了實現特定的功能。?? ?
2.2 著色器內置變量
1) 頂點著色器內置變量
名稱 | 類型 | 描述 |
---|---|---|
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輸出 |
2)片段著色器內置變量
名稱 | 類型 | 描述 |
---|---|---|
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 | 輸出的深度用于隨后的像素操作,如果這個值沒有被寫,則使用固定功能管線的深度值代替 |
三、最常見內置變量使用范例
3.1 常見著色器變量
內置變量名稱 | 含義 | 變量數值類型 |
---|---|---|
gl_PointSize | ?點渲染模式,方形點區域渲染像素大小 | ?float |
gl_Position? ? ? ? | 頂點位置坐標?? | ?vec4 |
gl_FragColor? ? ? | 片元顏色值?? ? | vec4 |
gl_FragCoord? ? ? | 片元坐標,單位像素?? | ?vec2 |
gl_PointCoord?? ? | 點渲染模式對應點像素坐標?? ? | vec2 |
????????當WebGL執行繪制函數gl.drawArrays()繪制模式是點模式gl.POINTS的時候,頂點著色器語言main函數中才會用到內置變量gl_PointSize,使用內置變量gl_PointSize主要是用來設置頂點渲染出來的方形點像素大小。
3.2 示例1: gl_PointSize?
void main() {//給內置變量gl_PointSize賦值像素大小,注意值是浮點數gl_PointSize=20.0;
}//繪制函數繪制模式:點gl.POINTS
gl.drawArrays(gl.POINTS,0,點數量);
3.3 示例2:gl_Position?
????????gl_Position內置變量主要和頂點相關,出現的位置是頂點著色器語言的main函數中。gl_Position內置變量表示最終傳入片元著色器片元化要使用的頂點位置坐標。
????????如果只有一個頂點,直接在給頂點著色器中設置內置變量gl_Position賦值就可以,內置變量gl_Position的值是四維向量vec4(x,y,z,1.0),前三個參數表示頂點的xyz坐標值,第四個參數是浮點數1.0。
void main() {//頂點位置,位于坐標原點gl_Position = vec4(0.0,0.0,0.0,1.0);
}
????????如果你想完全理解內置變量gl_Position,必須建立逐頂點的概念,如果javascript語言中出現一個變量賦值,你可以理解為僅僅執行一次,但是對于著色器中不能直接這么理解,如果有多個頂點,你可以理解為每個頂點都要執行一遍頂點著色器主函數main中的程序。
????????多個頂點的時候,內置變量gl_Position對應的值是attribute關鍵字聲明的頂點位置坐標變量apos,頂點位置坐標變量apos變量對應了javascript代碼中多個頂點位置數據。
<!-- 頂點著色器源碼 -->
<script id="vertexShader" type="x-shader/x-vertex">
? //attribute聲明vec4類型變量apos
? attribute vec4 apos;
? void main() {
? ? //頂點坐標apos賦值給內置變量gl_Position
? ? //逐頂點處理數據
? ? gl_Position = apos;
? }
</script>
????????逐頂點處理的案例:WebGL的每一個頂點位置坐標都會通過平移矩陣m4進行矩陣變換,相當于批量操作所有的頂點數據,進行了平移,只是平移的計算通過矩陣乘法運算完成的而已。所謂的逐頂點,在這里體現的就是每一個頂點都會執行main函數中的矩陣變換。你可以參照生活的流水線去理解,比如多個同樣的設備從我這里經過,我會分別對他們進行同樣的操作,比如安裝一個零件。
<!-- 頂點著色器源碼 -->
<script id="vertexShader" type="x-shader/x-vertex">
? //attribute聲明vec4類型變量apos
? attribute vec4 apos;
? void main() {
? ? //創建平移矩陣(沿x軸平移-0.4)
? ? //1 ? 0 ? 0 ?-0.4
? ? //0 ? 1 ? 0 ? ?0
? ? //0 ? 0 ? 1 ? ?0
? ? //0 ? 0 ? 0 ? ?1
? ? mat4 m4 = mat4(1,0,0,0, ?0,1,0,0, ?0,0,1,0, ?-0.4,0,0,1);
? ? //平移矩陣m4左乘頂點坐標(vec4類型數據可以理解為線性代數中的nx1矩陣,即列向量)
? ? // 逐頂點進行矩陣變換
? ? gl_Position = m4*apos;
? }
</script>
## gl_Position的頂點數據傳遞
attribute聲明的頂點變量數據如何通過javascript的WebGL API批量傳遞所有頂點數據。
<script>
? ? //頂點著色器源碼
? ? var vertexShaderSource = document.getElementById( 'vertexShader' ).innerText;
? ? //片元著色器源碼
? ? var fragShaderSource = document.getElementById( 'fragmentShader' ).innerText;
? ? //初始化著色器
? ? var program = initShader(gl,vertexShaderSource,fragShaderSource);
? ? //獲取頂點著色器的位置變量apos,即aposLocation指向apos變量。
? ? var aposLocation = gl.getAttribLocation(program,'apos');
? ? //類型數組構造函數Float32Array創建頂點數組
? ? var data=new Float32Array([0.5,0.5,-0.5,0.5,-0.5,-0.5,0.5,-0.5]);
? ? //創建緩沖區對象
? ? var buffer=gl.createBuffer();
? ? //綁定緩沖區對象,激活buffer
? ? gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
? ? //頂點數組data數據傳入緩沖區
? ? gl.bufferData(gl.ARRAY_BUFFER,data,gl.STATIC_DRAW);
? ? //緩沖區中的數據按照一定的規律傳遞給位置變量apos
? ? gl.vertexAttribPointer(aposLocation,2,gl.FLOAT,false,0,0);
? ? //允許數據傳遞
? ? gl.enableVertexAttribArray(aposLocation);
...
</script>
3.4 示例3:gl_FragColor
gl_FragColor內置變量主要用來設置片元像素的顏色,出現的位置是片元著色器語言的main函數中。
內置變量gl_Position的值是四維向量vec4(r,g,b,a),前三個參數表示片元像素顏色值RGB,第四個參數是片元像素透明度A,1.0表示不透明,0.0表示完全透明。
// 片元顏色設置為紅色
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
理解內置變量gl_Position需要建立逐頂點的概念,對于內置變量gl_FragColor而言,需要建立逐片元的概念。頂點經過片元著色器片元化以后,得到一個個片元,或者說像素點,然后通過內置變量gl_FragColor給每一個片元設置顏色值,所有片元可以使用同一個顏色值,也可能不是同一個顏色值,可以通過特定算法計算或者紋理像素采樣。
根據位置設置漸變色
? void main() {
? ? // 片元沿著x方向漸變
? ? gl_FragColor = vec4(gl_FragCoord.x/500.0*1.0,1.0,0.0,1.0);
? }
紋理采樣
// 接收插值后的紋理坐標
varying vec2 v_TexCoord;
// 紋理圖片像素數據
uniform sampler2D u_Sampler;
void main() {
? // 采集紋素,逐片元賦值像素值
? gl_FragColor = texture2D(u_Sampler,v_TexCoord);
}
片元坐標gl_FragCoord
內置變量gl_FragCoord表示WebGL在canvas畫布上渲染的所有片元或者說像素的坐標,坐標原點是canvas畫布的左上角,x軸水平向右,y豎直向下,gl_FragCoord坐標的單位是像素,gl_FragCoord的值是vec2(x,y),通過gl_FragCoord.x、gl_FragCoord.y方式可以分別訪問片元坐標的縱橫坐標。
下面代碼是把canvas畫布上不同區域片元設置為不同顏色。
<!-- 片元著色器源碼 -->
<script id="fragmentShader" type="x-shader/x-fragment">
? void main() {
? ? // 根據片元的x坐標,來設置片元的像素值
? ? if(gl_FragCoord.x < 300.0){
? ? ? // canvas畫布上[0,300)之間片元像素值設置
? ? ? gl_FragColor = vec4(1.0,0.0,0.0,1.0);
? ? }else if (gl_FragCoord.x <= 400.0) {
? ? ? // canvas畫布上(300,400]之間片元像素值設置
? ? ? gl_FragColor = vec4(0.0,1.0,0.0,1.0);
? ? }else {
? ? ? // canvas畫布上(400,500]之間片元像素值設置
? ? ? gl_FragColor = vec4(0.0,0.0,1.0,1.0);
? ? } ? ?
? ? // 所有片元設置為紅色
? ? // gl_FragColor = vec4(1.0,0.0,0.0,1.0);
? }
</script>
片元的顏色隨著坐標變化(設置一個漸變色效果)
<!-- 片元著色器源碼 -->
<script id="fragmentShader" type="x-shader/x-fragment">
? void main() {
? ? // 片元沿著x方向漸變
? ? gl_FragColor = vec4(gl_FragCoord.x/500.0*1.0,1.0,0.0,1.0);
? }
</script>
3.5 渲染點片元坐標gl_PointCoord
????????如果你想了解內置變量gl_PointCoord表示的坐標含義,就需要了解 GL繪制函數gl.drawArrays()的繪制模式參數gl.POINTS。
????????繪制函數gl.drawArrays()繪制模式參數設置為點渲染模式gl.POINTS,WebGL會把頂點渲染為一個方形區域,在頂點著色器代碼中可以通過內置變量gl_PointSize設置頂點渲染的方向區域像素大小。
????????一個頂點渲染為一個方形區域,每個方形區域可以以方向區域的左上角建立一個直角坐標系,然后使用內置變量gl_PointCoord描述每個方形區域中像素或者說片元的坐標,比如方形區域的左上角坐標是(0.0,0.0),每個方形區域幾何中心坐標是(0.5,0.5),右下角坐標是(1.0,1.0)。
????????注意內置變量gl_PointCoord和gl_FragCoord表示的像素坐標含義不同,查看下圖表示。
// 點繪制模式渲染10個頂點
gl.drawArrays(gl.POINTS,0,10);
頂點著色器中通過內置變量gl_PointSize設置點渲染的方形區域像素尺寸。
void main() {
? //點渲染的方形區域像素大小
? gl_PointSize = 20.0;
? ...
}
3.6 gl_PointCoord應用案例
????????gl.POINTS繪制模式點默認渲染效果是方形區域,通過下面片元著色器代碼設置可以把默認渲染效果更改為圓形區域。
<!-- 片元著色器源碼 -->
<script id="fragmentShader" type="x-shader/x-fragment">
? precision lowp float;// 所有float類型數據的精度是lowp
? void main() {
? ? // 計算方形區域每個片元距離方形幾何中心的距離
? ? // gl.POINTS模式點渲染的方形區域,方形中心是0.5,0.5,左上角是坐標原點,右下角是1.0,1.0,
? ? float r = distance(gl_PointCoord, vec2(0.5, 0.5));
? ? //根據距離設置片元
? ? if(r < 0.5){
? ? ? // 方形區域片元距離幾何中心半徑小于0.5,像素顏色設置紅色
? ? ? gl_FragColor = vec4(1.0,0.0,0.0,1.0);
? ? }else {
? ? ? // 方形區域距離幾何中心半徑不小于0.5的片元剪裁舍棄掉:
? ? ? discard;
? ? }
? }
</script>
????????通過gl_PointCoord返回的是片元縱橫坐標vec2(x,y),自然通過xy分量gl_PointCoord.x、gl_PointCoord.y方式可以分別訪問片元坐標的橫坐標、縱坐標,
? ? ? ? ? ? ? ? ? ? ? ??
四、GPU的內置函數
4. 1 內置函數列表
4.2 角度與三角函數
4.3 指數函數
4.4 通用函數
?