OpenGL ES2 學習教程4——Shader語言

shader語言能夠當作是特殊的C語言,專門用來建立頂點片斷着色器程序的語言。像第二節裏的程序數組

// vertex shader
attribute vec4 vPosition;
void main() {
  gl_Position = vPosition;
}
// fragment shader
precision mediump float;
void main() {
  gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}

基本類型

  • 標量 float int boolapp

  • 浮點矢量 float vec2 vec3 vec4函數

  • 整數矢量 int ivec2 ivec3 ivec4工具

  • 布爾矢量 bool bvec2 bvec3 bvec4oop

  • 矩陣 mat2 mat3 mat4(分別是22,33,4*4的浮點型矩陣)性能

  • void類型(表示沒函數返回或空的參數)void測試

  • 採樣器(用於指定紋理)sampler2D samplerCube優化

結構體和數組

struct type-name { // 結構體不支持嵌套
    members
} struct-name;  // 結構體也能夠聲明爲數組,struct-name[]

float foo[3];
// 只支持一維數組

修飾符(限定符)

  • none 默認限定符:默認定義變量都是none,局部可讀寫變量或參數。ui

  • const 常量限定符:編譯時的常量,或表示只讀的函數參數,結構體的成員不能聲明爲常量,結構體變量能夠。code

  • attribute 屬性限定符:能夠由應用程序指定經過GLES傳給頂點着色器的每個頂點數據,只能用在頂點着色器。值爲只讀,只能被是定爲float vec2 vec3 vec4 mat2 mat3 mat4,不能被定義爲數組和結構體。GLES規定至少支持8個屬性,每一個屬性被存儲爲4個份量的存儲單元,所以能夠將float這樣的變量組合爲一個vec4來節約空間。典型的被用來儲存位置、法線、貼圖座標和顏色數據。着色器裏被聲明爲屬性的變量是隻讀資源,不能被修改。

  • uniform 全侷限定符:在圖元處理期間不會被改變的值,能夠由應用程序經過GLES傳給頂點片斷着色器的全局變量。被全部的着色器共享。uniform存儲各類着色器須要的數據,例如:轉換矩陣、光照參數或者顏色。基本上各類輸入着色器的常量參數像頂點和片斷(但在編譯時並不知道)都應該是uniform。他們在硬件中被放在稱爲「常量存儲區(constant store)「中。一樣它也有數量限制的,GLES規定至少128個頂點着色器uniform和16個片斷着色器uniform。

  • varying 易變限定符:通過插值的易變變量,由頂點着色器傳給片斷着色器,易變變量在頂點着色器和片斷着色器中要使用相同的類型和名字。只有在片斷着色器中靜態使用的易變變量才須要在頂點着色器中成對定義。不能用結構體定義,只能聲明爲浮點型標量,矢量和矩陣。一樣有數量限制。包括屬性和全局變量最大值都由glGetIntegerv查詢(GL_MAX_VERTEX_ATTRIBUTE,GL_MAX_VERTEX_UNIFORM_VECTORS,GL_MAX_FRAGMENT_UNIFORM_VECTORS,GL_MAX_VARYING_VECTORS)。

GLint maxVertexAttribs;
GLint maxVertexUniforms;
GLint maxFragmentUniforms;
GLint maxVaryings;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs); 
glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &maxVertexUniforms);
glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &maxFragmentUniforms);
glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
//在我手機上的輸出:
//I/GLES-Tutorial(18378): maxVertexAttribs: 16
//I/GLES-Tutorial(18378): maxVertexUniforms: 256
//I/GLES-Tutorial(18378): maxFragmentUniforms: 224
//I/GLES-Tutorial(18378): maxVaryings: 16

構造器

shader語言有着很是嚴格的類型判斷,不支持隱式轉化,類型的轉化必須用構造器。

float fA = 1.0;
bool bB = true;
int iC = 0;
fA = float(bB); // convert bool to float

vec4 myVec4 = vec4(1.0); // myVec4 = {1.0, 1.0, 1.0, 1.0}
vec3 myVec3 = vec3(1.0, 0.0, 0.5);
vec3 temp = vec3(myVec3);

struct light {
    float intensity;
    vec3 position;
};
light lightVar = light(3.0, vec3(1.0));

份量

矢量的份量名稱:{x,y,z,w}表示頂點; {r,g,b,a}表示顏色;{s,t,p,q}表示紋理座標。

每一個份量用點號鏈接(例如v2.x(一個float變量),v3.rg(一個vec2變量))。

不一樣組的份量不能混合使用(例如v4.xgba不合法),可是順序能夠任意,能夠重複(例如v3.yyxx(一個vec4變量)),但不能超過4個,由於編譯器不知道轉化成什麼類型(例如v4.xyzwxy不合法)。

矩陣的份量就是用下標表示,注意的是矩陣是以列優先的。

mat4 m;
m[1] = vec4(1.0); // 矩陣第二列設置爲{1.0, 1.0, 1.0, 1.0}
m[2][0] = 1.0;

操做符

和C語言相似,可是更加嚴格。執行操做的變量必須是相同的基本類型,二進制運算加減乘除必須是浮點型或整型。

函數

函數參數須要加上限定詞,指示這個變量是否可以被函數修改。

舉個栗子:

vec4 myFunc(inout float myFloat, // inout parameter 
            mat4 myMat4,         // in parameter (default)
            out vec4 myVec4);    // out parameter
  • in 默認修飾符,表示爲輸入,不能被函數修改

  • inout 表示爲引用,能夠被修改

  • out 表示不是函數輸入,它的值在函數返回後將被修改

shader語言提供許多內置函數,例如dot

流程控制語句

Shader語言支持簡單的if-else;可是條件結果必須是布爾值。

循環語句限制很是嚴格:必須有循環迭代變量,他必須是增長或減小的,中止的條件必須匹配索引而且爲常量表達式,在循環內部不能改變迭代的值。這些限制使得編譯器可以把循環語句展開。

// 合法的栗子
for (int i = 0; i < 5; i++)
{
    sum += i;
}
// 不合法的栗子1
float myArray[5];
for (int i = 0; i < 5; i++)
{
    sum += myArray[i] // 不容許出現很是量表達式
}
// 不合法的栗子2
uniform in loopIter;
for (int i = 0; i < loopIter; i++) // 中止條件不是常量表達式
{
    sum += i;
}

預處理指令

#define  #undef  #if  #ifdef  #ifndef  #else  #elif  #endif
__LINE__    // 在着色器中的當前行號
__FILE__    // GLES2中老是0
__VERSION__ // GLES的版本 (e.g., 100)
GL_ES       // 被定義爲1

#version 100   // GLES Shading Language v1.00, 老是要放在最開頭

#extension extension_name : behavior
// behavior能夠是require, enable, warn,disable
#extension GL_OES_texture_3D : enable  // 若是3D貼圖擴展不被支持讓預編譯產生警告

注意和C++不一樣,宏不能帶參數。

精度控制

精度控制可以被使用在任何浮點和整型數變量。能夠設置爲高highp,中mediump,低lowp。

highp vec4 position;
varying lowp vec4 color;
// 默認的精度能夠這麼設置在頭部
precision highp float;
precision mediump int;

不變性

GLES中,invariance是被用於任何頂點着色器的變量輸出的關鍵字。因爲着色器編譯時可能進行優化,一些指令被從新整理,可能兩個着色器中間相同的計算產出不一樣的值來。在多通道着色器的特殊狀況下,一樣的物體使用透明混合(alpha blending)來繪製時能形成清晰度的不一樣。引入invariance,着色器會讓一樣的輸入計算後輸出的值相同。

invariant gl_Position;  // 聲明不變性輸出

// 可使用#pragma來保證全局變量的不變性
#pragma STDGL invariant(all)  // 它將限制編譯器的優化,除非必要最好不用,會致使性能降低

編輯工具

在Mac下可使用Shader Builder(apple-opengl找到 graphics tools的連接,去下載對應你XCode版本的)來編寫、運行、測試OpenGL shaders

相關文章
相關標籤/搜索