OpenGL ES入門02-OpenGL ES著色器

前言

本文是關于OpenGL ES的系統(tǒng)性學習過程涂佃,記錄了自己在學習OpenGL ES時的收獲。
這篇文章的目標是學習OpenGL ES著色器語言咆贬。
環(huán)境是Xcode8.1+OpenGL ES 2.0
目前代碼已經放到github上面,OpenGL ES入門02-OpenGL ES著色器

歡迎關注我的 OpenGL ES入門專題

概述

著色器(Shader)是運行在GPU上的小程序。這些小程序為圖形渲染管線的某個特定部分而運行缴阎。從基本意義上來說,著色器只是一種把輸入轉化為輸出的程序简软。著色器也是一種非常獨立的程序蛮拔,因為它們之間不能相互通信;它們之間唯一的溝通只有通過輸入和輸出替饿。

效果

三角形繪制

著色器語言

著色器是使用一種叫GLSL的類C語言寫成的语泽。GLSL是為圖形計算量身定制的,它包含一些針對向量和矩陣操作的有用特性视卢。

著色器分類

頂點著色器 是一個可編程的處理單元踱卵,執(zhí)行頂點變換、紋理坐標變換据过、光照惋砂、材質等頂點的相關操作,每頂點執(zhí)行一次绳锅。替代了傳統(tǒng)渲染管線中頂點變換西饵、光照以及紋理坐標的處理。

attribute vec3 position;
attribute vec3 color;
varying vec3 outColor;

void main()
{
    gl_Position = vec4(position, 1.0);
    outColor = color;
}

片元著色器 是一個處理片元值及其相關聯(lián)數據的可編程單元鳞芙,片元著色器可執(zhí)行紋理的訪問眷柔、顏色的匯總期虾、霧化等操作,每片元執(zhí)行一次驯嘱。

precision mediump float;
varying vec3 outColor;
void main()
{
    gl_FragColor = vec4(outColor, 1.0);
}

數據類型

類型 說明
float 浮點型
bool 布爾型
int 整形
vec2 包含了2個浮點數的向量
vec3 包含了3個浮點數的向量
vec4 包含了4個浮點數的向量
ivec2 包含了2個整數的向量
ivec3 包含了3個整數的向量
ivec4 包含了4個整數的向量
bvec2 包含了2個布爾數的向量
bvec3 包含了3個布爾數的向量
bvec4 包含了4個布爾數的向量
mat2 2*2維矩陣
mat3 3*3維矩陣
mat4 4*4維矩陣
sampler1D 1D紋理采樣器
sampler2D 2D紋理采樣器
sampler3D 3D紋理采樣器
samplerCube Cube紋理采樣器

常量

const 可以用來修飾任何基本數據類型镶苞。通常const變量在聲明的同時要進行初始化,結構體字段不能使用const修飾嗎鞠评,但是變量可以茂蚓,并通過構造器進行初始化。包含數組的數組和結構體不能聲明為常量剃幌,因為它們不能被初始化聋涨。

onst vec4 color = vec4 (1.0, 1.0, 1.0, 1.0);

存儲修飾符

attribute 變量(屬性變量)只能用于頂點著色器中,不能用于片元著色器负乡。 一般用該變量來表示一些頂點數據牍白,如:頂點坐標、紋理坐標敬鬓、顏色等淹朋。

uniforms 是一種從CPU中的應用向GPU中的著色器發(fā)送數據的方式,但uniform和頂點屬性有些不同钉答。首先础芍,uniform是全局的(Global)。全局意味著uniform變量必須在每個著色器程序對象中都是獨一無二的数尿,而且它可以被著色器程序的任意著色器在任意階段訪問仑性。第二,無論你把uniform值設置成什么右蹦,uniform會一直保存它們的數據诊杆,直到它們被重置或更新。

samplers 一種特殊的 uniform何陆,用于呈現紋理晨汹。sampler 可用于頂點著色器和片元著色器。

varying 變量(易變變量)是從頂點著色器傳遞到片元著色器的數據變量贷盲。頂點著色器可以使用易變變量來傳遞需要插值的顏色淘这、法向量、紋理坐標等任意值巩剖。 在頂點與片元shader程序間傳遞數據是很容易的铝穷,一般在頂點shader中修改varying變量值,然后片元shader中使用該值佳魔,當然,該變量在頂點及片元這兩段shader程序中聲明必須是一致的 鞠鲜。例如:上面代碼中應用程序中由頂點著色器傳入片元著色器中的vColor變量断国。

精度修飾符

精度修飾符

precision 可以用來確定默認精度修飾符朦佩。類型可以是int或float或采樣器類型,precision-qualifier可以是lowp, mediump, 或者highp语稠。任何其他類型和修飾符都會引起錯誤。如果type是float類型弄砍,那么該精度(precision-qualifier)將適用于所有無精度修飾符的浮點數聲明(標量仙畦,向量,矩陣)音婶。如果type是int類型慨畸,那么該精度(precision-qualifier)將適用于所有無精度修飾符的整型數聲明(標量,向量)衣式。包括全局變量聲明寸士,函數返回值聲明,函數參數聲明碴卧,和本地變量聲明等弱卡。沒有聲明精度修飾符的變量將使用和它最近的precision語句中的精度。

precision highp float;
precision highp int;
precision lowp sampler2D;
precision lowp samplerCube;

內建變量

gl_Position 頂點著色器內建變量住册,表示變換后點的空間位置婶博。 頂點著色器從應用程序中獲得原始的頂點位置數據,這些原始的頂點數據在頂點著色器中經過平移荧飞、旋轉凡人、縮放等數學變換后,生成新的頂點位置叹阔。新的頂點位置通過在頂點著色器中寫入gl_Position傳遞到渲染管線的后繼階段繼續(xù)處理挠轴。

*** gl_PointSize*** 頂點著色器內置變量,設置柵格化點的直徑,也就是點的大小,通常用于點精靈耳幢,粒子等繪制岸晦。

gl_FragColor 片元著色器內置變量,用來保存片元著色器計算完成的片元顏色值帅掘,此顏色值將送入渲染管線的后繼階段進行處理委煤。

加載著色器

static GLuint createGLShader(const char *shaderText, GLenum shaderType)
{
    GLuint shader = glCreateShader(shaderType);
    glShaderSource(shader, 1, &shaderText, NULL);
    glCompileShader(shader);
    
    int compiled = 0;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
    if (!compiled) {
        GLint infoLen = 0;
        glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &infoLen);
        if (infoLen > 1) {
            char *infoLog = (char *)malloc(sizeof(char) * infoLen);
            if (infoLog) {
                glGetShaderInfoLog (shader, infoLen, NULL, infoLog);
                GLlog("Error compiling shader: %s\n", infoLog);
                free(infoLog);
            }
        }
        glDeleteShader(shader);
        return 0;
    }
    return shader;
}

1、創(chuàng)建著色器修档,通過glCreateShader創(chuàng)建著色器碧绞,type為著色器的類型GL_VERTEX_SHADER 和 GL_FRAGMENT_SHADER

glCreateShader (GLenum type) //type: GL_VERTEX_SHADER 或者 GL_FRAGMENT_SHADER

2、添加著色器源程序吱窝,將著色器源碼關聯(lián)到一個著色器對象shader上讥邻。string是一個有count行GLchar類型的字符串組成的數組迫靖,用來表示著色器的源代碼數據。string可以以NULL結尾兴使,也可以不是系宜。如果length為NULL則string給出的每行都是以NULL結尾,否則length中必須有count個表示string長度的元素盹牧。(也就是說字符串以NULL結尾我們不用指定長度汰寓,否則必須制定每行的長度)

glShaderSource (GLuint shader, GLsizei count, const GLchar* const *string, const GLint* length)

3有滑、編譯著色器源程序

glCompileShader (GLuint shader)

4毛好、刪除著色器

glDeleteShader (GLuint shader)

5苛秕、容錯處理想帅,通過glGetShaderiv獲取編譯狀態(tài),通過glGetShaderInfoLog獲取錯誤信息旨剥。

#define GL_COMPILE_STATUS                                0x8B81
#define GL_INFO_LOG_LENGTH                               0x8B84
glGetShaderiv (GLuint shader, GLenum pname, GLint* params) 
glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)

創(chuàng)建著色器程序

GLuint createGLProgram(const char *vertext, const char *frag)
{
    GLuint program = glCreateProgram();
    
    GLuint vertShader = createGLShader(vertext, GL_VERTEX_SHADER);
    GLuint fragShader = createGLShader(frag, GL_FRAGMENT_SHADER);
    
    if (vertShader == 0 || fragShader == 0) {
        return 0;
    }
    
    glAttachShader(program, vertShader);
    glAttachShader(program, fragShader);
    
    glLinkProgram(program);
    GLint success;
    glGetProgramiv(program, GL_LINK_STATUS, &success);
    if (!success) {
        GLint infoLen;
        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
        if (infoLen > 1) {
            GLchar *infoText = (GLchar *)malloc(sizeof(GLchar)*infoLen + 1);
            if (infoText) {
                memset(infoText, 0x00, sizeof(GLchar)*infoLen + 1);
                glGetProgramInfoLog(program, infoLen, NULL, infoText);
                GLlog("%s", infoText);
                free(infoText);
            }
        }
        glDeleteShader(vertShader);
        glDeleteShader(fragShader);
        glDeleteProgram(program);
        return 0;
    }
    
    glDetachShader(program, vertShader);
    glDetachShader(program, fragShader);
    glDeleteShader(vertShader);
    glDeleteShader(fragShader);
  
    return program;
}

1、創(chuàng)建著色器程序

 glCreateProgram (void)

2衩椒、裝配著色器

glAttachShader (GLuint program, GLuint shader)

3毛萌、鏈接著色器程序

glLinkProgram (GLuint program)

4、卸載著色器程序

glDetachShader (GLuint program, GLuint shader)

5膏秫、使用著色器程序

 glUseProgram (GLuint program)

6缤削、容錯處理

#define GL_LINK_STATUS                                   0x8B82
#define GL_INFO_LOG_LENGTH                               0x8B84
glGetProgramiv (GLuint program, GLenum pname, GLint* params)
glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)

三角形繪制

- (void)setupGLProgram
{
    NSString *vertFile = [[NSBundle mainBundle] pathForResource:@"vert.glsl" ofType:nil];
    NSString *fragFile = [[NSBundle mainBundle] pathForResource:@"frag.glsl" ofType:nil];
    _program = createGLProgramFromFile(vertFile.UTF8String, fragFile.UTF8String);
    
    glUseProgram(_program);
}

- (void)setupVertexData
{
   // 需要加static關鍵字亭敢,否則數據傳輸存在問題 
   static GLfloat vertices[] = {
        0.0f,  0.5f, 0.0f,
        -0.5f, -0.5f, 0.0f,
        0.5f, -0.5f, 0.0f
    };
    GLint posSlot = glGetAttribLocation(_program, "position");
    glVertexAttribPointer(posSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices);
    glEnableVertexAttribArray(posSlot);
    
   //顏色數據
    static GLfloat colors[] = {
        0.0f, 1.0f, 1.0f,
        1.0f, 0.0f, 1.0f,
        1.0f, 1.0f, 0.0f
    };
    GLint colorSlot = glGetAttribLocation(_program, "color");
    glVertexAttribPointer(colorSlot, 3, GL_FLOAT, GL_FALSE, 0, colors);
    glEnableVertexAttribArray(colorSlot);
}

- (void)render
{
    glClearColor(1.0, 1.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    
    glViewport(0, 0, self.frame.size.width, self.frame.size.height);

// 在這里初始化數據帅刀,可以加static關鍵字劝篷,也可以不加
//    GLfloat vertices[] = {
//         0.0f,  0.5f, 0.0f,
//        -0.5f, -0.5f, 0.0f,
//         0.5f, -0.5f, 0.0f
//    };
//    GLint posSlot = glGetAttribLocation(_program, "position");
//    glVertexAttribPointer(posSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices);
//    glEnableVertexAttribArray(posSlot);
//    
//    GLfloat colors[] = {
//        0.0f, 1.0f, 0.0f,
//        0.0f, 1.0f, 0.0f,
//        0.0f, 1.0f, 0.0f
//    };
//    GLint colorSlot = glGetAttribLocation(_program, "color");
//    glVertexAttribPointer(colorSlot, 3, GL_FLOAT, GL_FALSE, 0, colors);
//    glEnableVertexAttribArray(colorSlot);
    
    [self setupVertexData];
    
    glDrawArrays(GL_TRIANGLES, 0, 3);
    
    //將指定 renderbuffer 呈現在屏幕上娇妓,在這里我們指定的是前面已經綁定為當前 renderbuffer 的那個哈恰,在 renderbuffer 可以被呈現之前着绷,必須調用renderbufferStorage:fromDrawable: 為之分配存儲空間锌云。
    [_context presentRenderbuffer:GL_RENDERBUFFER];
}
glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
indx 指定要修改的頂點著色器中頂點變量id桑涎;
size 指定每個頂點屬性的組件數量。必須為1娃胆、2里烦、3或者4禁谦。
type 指定數組中每個組件的數據類型∩フ海可用的符號常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED, 和 GL_FLOAT触趴,初始值為GL_FLOAT;
normalized 指定當被訪問時爽冕,固定點數據值是否應該被歸一化(GL_TRUE)或者直接轉換為固定點值(GL_FALSE)披蕉;
stride 指定連續(xù)頂點屬性之間的偏移量没讲。如果為0,那么頂點屬性會被理解為:它們是緊密排列在一起的徙缴。初始值為0于样;
ptr 頂點數據指針。

參考鏈接

https://www.khronos.org/opengles/sdk/docs/reference_cards/OpenGL-ES-2_0-Reference-card.pdf

http://www.cnblogs.com/kesalin/archive/2012/11/25/opengl_es_tutorial_02.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市卦溢,隨后出現的幾起案子,更是在濱河造成了極大的恐慌贬芥,老刑警劉巖凄贩,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件昵时,死亡現場離奇詭異椒丧,居然都是意外死亡,警方通過查閱死者的電腦和手機壶熏,發(fā)現死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門溯职,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人叹俏,你說我怎么就攤上這事僻族。” “怎么了蝌数?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵顶伞,是天一觀的道長枝哄。 經常有香客問我阻荒,道長侨赡,這世上最難降的妖魔是什么粱侣? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任齐婴,我火速辦了婚禮柠偶,結果婚禮上,老公的妹妹穿的比我還像新娘诱担。我一直安慰自己蔫仙,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布屎勘。 她就那樣靜靜地躺著概漱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪犀概。 梳的紋絲不亂的頭發(fā)上姻灶,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天产喉,我揣著相機與錄音敢会,去河邊找鬼。 笑死塞俱,一個胖子當著我的面吹牛吏垮,可吹牛的內容都是我干的。 我是一名探鬼主播唯蝶,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼遗嗽,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了痹换?” 一聲冷哼從身側響起晴音,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤锤躁,失蹤者是張志新(化名)和其女友劉穎或详,沒想到半個月后霸琴,有當地人在樹林里發(fā)現了一具尸體昭伸,經...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡选调,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年仁堪,在試婚紗的時候發(fā)現自己被綠了填渠。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片氛什。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡捺檬,死狀恐怖贸铜,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤渤早,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布瘫俊,位于F島的核電站扛芽,受9級特大地震影響,放射性物質發(fā)生泄漏川尖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一缰贝、第九天 我趴在偏房一處隱蔽的房頂上張望剩晴。 院中可真熱鬧侵状,春花似錦趣兄、人聲如沸绽左。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽闯团。三九已至,卻和暖如春仙粱,著一層夾襖步出監(jiān)牢的瞬間房交,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工伐割, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留候味,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓隔心,卻偏偏與公主長得像白群,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子硬霍,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內容