iOS OpenGL ES繪制三角形

OpenGLES繪制三角形

最近工作需要用到OpenGL ES和GPUImage,在這里記錄一下自己學(xué)習(xí)到的知識(shí)

OpenGL ES是什么

OpenGL(Open Graphics Library)定義了一個(gè)跨編程語言、跨平臺(tái) 編程的專業(yè)圖形程序接口∏城牵可用于二維或三維圖像的處理與渲染设凹,它是 一個(gè)功能強(qiáng)大案站、調(diào)用方便的底層圖形庫痛黎。對(duì)于嵌入式的設(shè)備,其提供了 OpenGL ES(OpenGL for Embedded Systems)版本以躯,該版本是針對(duì)手 機(jī)槐秧、Pad等嵌入式設(shè)備而設(shè)計(jì)的啄踊,是OpenGL的一個(gè)子集。

OpenGL 渲染流程

在OpenGL中刁标,任何事物都在3D空間中颠通,而屏幕和窗口卻是2D像素?cái)?shù)組,這導(dǎo)致OpenGL的大部分工作都是關(guān)于把3D坐標(biāo)轉(zhuǎn)變?yōu)檫m應(yīng)你屏幕的2D像素膀懈。3D坐標(biāo)轉(zhuǎn)為2D坐標(biāo)的處理過程是由OpenGL的圖形渲染管線(Graphics Pipeline顿锰,大多譯為管線,實(shí)際上指的是一堆原始圖形數(shù)據(jù)途經(jīng)一個(gè)輸送管道启搂,期間經(jīng)過各種變化處理最終出現(xiàn)在屏幕的過程)管理的撵儿。

OpenGL 渲染流程如下圖幾個(gè)階段:


pipeline.png

iOS下使用OpenGL ES 流程

1. 創(chuàng)建自定義View并修改Layer

在iOS中一般使用CAEAGLLayer來實(shí)現(xiàn)OpenGL的各種功能,一般使用自定義的UIView狐血,并改變他的layer的類型。CAEAGLLayer默認(rèn)是透明的易核,官方建議設(shè)為不透明匈织。

self.eagLayer = (CAEAGLLayer *)self.layer;
[self setContentScaleFactor:[[UIScreen mainScreen] scale]];
self.eagLayer.opaque = YES;

2. 創(chuàng)建Context上下文

EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (![EAGLContext setCurrentContext:context]) {
    NSLog(@"Fail to set current context");
}
self.context = context;

3. 創(chuàng)建渲染緩存(Render Buffer)

render buffer用來存儲(chǔ)即將繪制到屏幕上的圖像數(shù)據(jù),理解為幀緩沖的一個(gè)附件牡直,用來真正存儲(chǔ)圖像的數(shù)據(jù)缀匕。

// 創(chuàng)建幀緩沖區(qū)
glGenRenderbuffers(1, &_renderBuffer);
// 綁定幀緩沖區(qū)到渲染管線
glBindRenderbuffer(GL_RENDERBUFFER, self.renderBuffer);
// 為繪制緩沖區(qū)分配存儲(chǔ)區(qū):將CAEAGLLayer的繪制存儲(chǔ)區(qū)作為繪制緩沖區(qū)的存儲(chǔ)區(qū)
[self.context renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.eagLayer];

4. 創(chuàng)建幀緩沖 (Frame Buffer)

幀緩沖理解為多種緩沖的結(jié)合。

// 創(chuàng)建繪制緩沖區(qū)
glGenFramebuffers(1, &_frameBuffer);
// 邦定繪制緩沖區(qū)到渲染管線
glBindFramebuffer(GL_FRAMEBUFFER, self.frameBuffer);
// 將繪制緩沖區(qū)邦定到幀緩沖區(qū)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self.renderBuffer);

5. 創(chuàng)建Shader

Shader使用著色器語言GLSL(OpenGL Shading Language)編寫碰逸,主要需要編寫頂點(diǎn)著色器和片段著色器的實(shí)現(xiàn)乡小,頂點(diǎn)著色器將計(jì)算好的頂點(diǎn)傳入片段著色器,然后片段著色器計(jì)算像素最后的顏色輸出饵史。

Xcode新建兩個(gè)文件:shader.vsh和shader.fsh满钟,分別代表頂點(diǎn)著色器和片元著色器

shader.vsh內(nèi)容如下:

//attribute 關(guān)鍵字用來描述傳入shader的變量
attribute vec4 position;

void main()
{
    gl_Position = position; // gl_Position是vertex shader的內(nèi)建變量,gl_Position中的頂點(diǎn)值最終輸出到渲染管線中
}

shader.fsh內(nèi)容如下:

 void main()
{
    gl_FragColor = vec4(0.5, 0.5, 0.5, 1.0); // gl_FragColor是fragment shader的內(nèi)建變量胳喷,gl_FragColor中的像素值最終輸出到渲染管線中
}

6. 編譯和鏈接Shader并鏈接到著色器程序

- (BOOL)buildProgramWithShaders:(NSString *)vert frag:(NSString *)frag {
    GLuint verShader, fragShader;
    self.program = glCreateProgram();
    
    //編譯
    [self compileShader:&verShader type:GL_VERTEX_SHADER file:vert];
    [self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:frag];
    
    glAttachShader(self.program, verShader);
    glAttachShader(self.program, fragShader);
    
    //釋放不需要的shader
    glDeleteShader(verShader);
    glDeleteShader(fragShader);
    
    //鏈接
    glLinkProgram(self.program);
    GLint linkSuccess;
    glGetProgramiv(self.program, GL_LINK_STATUS, &linkSuccess);
    if (linkSuccess == GL_FALSE) { //連接錯(cuò)誤
        GLchar messages[256];
        glGetProgramInfoLog(self.program, sizeof(messages), 0, &messages[0]);
        NSString *messageString = [NSString stringWithUTF8String:messages];
        NSLog(@"error%@", messageString);
        return NO;
    }
    
    return YES;
}

- (void)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file {
    NSString *content = [NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil];
    const GLchar *source = [content UTF8String];
    
    *shader = glCreateShader(type);
    
    glShaderSource(*shader, 1, &source, NULL);
    
    glCompileShader(*shader);
}

7. 傳入頂點(diǎn)數(shù)據(jù)湃番,繪制三角形

- (void)render {
    //清屏為白色
    glClearColor(1.0, 1.0, 1.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    
    CGFloat scale = [[UIScreen mainScreen] scale]; //獲取視圖放大倍數(shù),可以把scale設(shè)置為1試試
    //設(shè)置gl渲染窗口大小
    glViewport(self.frame.origin.x * scale, self.frame.origin.y * scale, self.frame.size.width * scale, self.frame.size.height * scale); //設(shè)置視口大小
    
    //讀取shader文件路徑
    NSString* vertFile = [[NSBundle mainBundle] pathForResource:@"shader" ofType:@"vsh"];
    NSString* fragFile = [[NSBundle mainBundle] pathForResource:@"shader" ofType:@"fsh"];
    
    BOOL buildProgramSuccess = [self buildProgramWithShaders:vertFile frag:fragFile];
    if (!buildProgramSuccess) {
        return;
    }
    glUseProgram(self.program); //成功便使用吭露,避免由于未使用導(dǎo)致的的bug
    
    GLfloat attrArr[] =
    {
        1.0f, -0.5f, 0.0f,  // 右下
        0.0f, 0.5f, 0.0f,   // 上
        -1.0f, -0.5f, 0.0f  // 左下
    };
    
    GLuint attrBuffer;
    glGenBuffers(1, &attrBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, attrBuffer);
    //將頂點(diǎn)坐標(biāo)寫入頂點(diǎn)VBO
    glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_STATIC_DRAW);
    
    // 獲取參數(shù)索引
    GLuint position = glGetAttribLocation(self.program, "position");
    
    //告訴OpenGL該如何解析頂點(diǎn)數(shù)據(jù)
    glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, NULL);
    glEnableVertexAttribArray(position);
    
    //繪制三個(gè)頂點(diǎn)的三角形
    glDrawArrays(GL_TRIANGLES, 0, 3);
    
    //EACAGLContext 渲染OpenGL繪制好的圖像到EACAGLLayer
    [self.context presentRenderbuffer:GL_RENDERBUFFER];
}

這樣子運(yùn)行起來就可以看到一個(gè)灰色的三角形了

demo地址

參考:
你好吠撮,三角形

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市讲竿,隨后出現(xiàn)的幾起案子泥兰,更是在濱河造成了極大的恐慌,老刑警劉巖题禀,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鞋诗,死亡現(xiàn)場離奇詭異,居然都是意外死亡投剥,警方通過查閱死者的電腦和手機(jī)师脂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吃警,你說我怎么就攤上這事糕篇。” “怎么了酌心?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵拌消,是天一觀的道長。 經(jīng)常有香客問我安券,道長墩崩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任侯勉,我火速辦了婚禮鹦筹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘址貌。我一直安慰自己铐拐,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布练对。 她就那樣靜靜地躺著遍蟋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪螟凭。 梳的紋絲不亂的頭發(fā)上虚青,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音螺男,去河邊找鬼棒厘。 笑死,一個(gè)胖子當(dāng)著我的面吹牛烟号,可吹牛的內(nèi)容都是我干的绊谭。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼汪拥,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼达传!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起迫筑,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤宪赶,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后脯燃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體搂妻,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年辕棚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了欲主。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片邓厕。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖扁瓢,靈堂內(nèi)的尸體忽然破棺而出详恼,到底是詐尸還是另有隱情,我是刑警寧澤引几,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布昧互,位于F島的核電站,受9級(jí)特大地震影響伟桅,放射性物質(zhì)發(fā)生泄漏敞掘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一楣铁、第九天 我趴在偏房一處隱蔽的房頂上張望玖雁。 院中可真熱鬧,春花似錦盖腕、人聲如沸茄菊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至竖哩,卻和暖如春哭廉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背相叁。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來泰國打工遵绰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人增淹。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓椿访,卻偏偏與公主長得像,于是被迫代替她去往敵國和親虑润。 傳聞我的和親對(duì)象是個(gè)殘疾皇子成玫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353