OpenGL ES入門04-OpenGL ES VAO VBO緩存技術(shù)

前言

本文是關(guān)于OpenGL ES的系統(tǒng)性學(xué)習(xí)過程如筛,記錄了自己在學(xué)習(xí)OpenGL ES時的收獲。
這篇文章的目標(biāo)是通過OpenGL ES 3.0的VAO赃承,VBO等緩存技術(shù)進(jìn)行貝塞爾曲線的繪制妙黍。如果不明白貝塞爾曲線原理,請參考之前的博客 理解與運用貝塞爾曲線瞧剖。
環(huán)境是Xcode8.1+OpenGL ES 3.0
目前代碼已經(jīng)放到github上面拭嫁,OpenGL ES入門04-OpenGL ES VAO VBO FBO緩存

歡迎關(guān)注我的 OpenGL ES入門專題

實現(xiàn)效果

貝塞爾曲線

頂點緩存VBO

普通的頂點數(shù)組的傳輸,需要在繪制的時候頻繁地從CPU到GPU傳輸頂點數(shù)據(jù)抓于,這種做法效率低下做粤,為了加快顯示速度,顯卡增加了一個擴展 VBO (Vertex Buffer object)捉撮,即頂點緩存怕品。它直接在 GPU 中開辟一個緩存區(qū)域來存儲頂點數(shù)據(jù),因為它是用來緩存儲頂點數(shù)據(jù)巾遭,因此被稱之為頂點緩存肉康。使用頂點緩存能夠大大較少了CPU到GPU 之間的數(shù)據(jù)拷貝開銷闯估,因此顯著地提升了程序運行的效率。

  • 創(chuàng)建頂點緩存對象
void glGenBuffers (GLsizei n, GLuint* buffers);

參數(shù) n : 表示需要創(chuàng)建頂點緩存對象的個數(shù)
參數(shù) buffers :用于存儲創(chuàng)建好的頂點緩存對象句柄

  • 將頂點緩存對象設(shè)置為當(dāng)前數(shù)組緩存對象
void glBindBuffer (GLenum target, GLuint buffer);

參數(shù) target :指定綁定的目標(biāo)吼和,取值為 GL_ARRAY_BUFFER(用于頂點數(shù)據(jù)) 或 GL_ELEMENT_ARRAY_BUFFER(用于索引數(shù)據(jù))
參數(shù) buffer :頂點緩存對象句柄

  • 為頂點緩存對象分配空間
void glBufferData (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);

參數(shù) target:與 glBindBuffer 中的參數(shù) target 相同涨薪;
參數(shù) size :指定頂點緩存區(qū)的大小,以字節(jié)為單位計數(shù)炫乓;
參數(shù) data :用于初始化頂點緩存區(qū)的數(shù)據(jù)刚夺,可以為 NULL,表示只分配空間末捣,之后再由 glBufferSubData 進(jìn)行初始化览闰;
參數(shù) usage :表示該緩存區(qū)域?qū)蝗绾问褂么览猓闹饕康氖怯糜趯υ摼彺鎱^(qū)域做何種程度的優(yōu)化,比如經(jīng)常修改的數(shù)據(jù)可能就會放在GPU緩存中達(dá)到快速操作的目的。

|參數(shù)|解釋|
|:---:|:---:|
|GL_STATIC_DRAW|表示該緩存區(qū)不會被修改|
|GL_DYNAMIC_DRAW|表示該緩存區(qū)會被周期性更改|
|GL_STREAM_DRAW|表示該緩存區(qū)會被頻繁更改|

  • 更新頂點緩沖區(qū)數(shù)據(jù)
void glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);

參數(shù) offset: 表示需要更新的數(shù)據(jù)的起始偏移量歌豺;
參數(shù) size: 表示需要更新的數(shù)據(jù)的個數(shù)分瘦,也是以字節(jié)為計數(shù)單位银锻;
參數(shù) data: 用于更新的數(shù)據(jù)酥筝;

  • 釋放頂點緩存
void glDeleteBuffers (GLsizei n, const GLuint* buffers);

參數(shù) n : 表示頂點緩存對象的個數(shù)
參數(shù) buffers :頂點緩存對象句柄

頂點數(shù)組對象VAO

VAO的全名是Vertex ArrayObject。它不用作存儲數(shù)據(jù)圃酵,但它與頂點繪制相關(guān)柳畔。
它的定位是狀態(tài)對象,記錄存儲狀態(tài)信息郭赐。VAO記錄的是一次繪制中做需要的信息薪韩,這包括數(shù)據(jù)在哪里、數(shù)據(jù)格式是什么等信息捌锭。VAO其實可以看成一個容器俘陷,可以包括多個VBO。 由于它進(jìn)一步將VBO容于其中观谦,所以繪制效率將在VBO的基礎(chǔ)上更進(jìn)一步拉盾。目前OpenGL ES3.0及以上才支持頂點數(shù)組對象。

  • 創(chuàng)建頂點數(shù)組對象
 glGenVertexArrays (GLsizei n, GLuint* arrays) ;

參數(shù) n : 表示頂點數(shù)組對象的個數(shù)
參數(shù) arrays :頂點數(shù)組對象句柄

  • 將頂點數(shù)組對象設(shè)置為當(dāng)前頂點數(shù)組對象
glBindVertexArray (GLuint array) ;

參數(shù) arrays :頂點數(shù)組對象句柄

  • 釋放頂點數(shù)組對象
 glDeleteVertexArrays (GLsizei n, const GLuint* arrays);

參數(shù) n : 表示頂點數(shù)組對象的個數(shù)
參數(shù) arrays :頂點數(shù)組對象句柄

注意:如果需要在OpenGL ES2.0上使用VAO豁状,可以使用蘋果擴展的相關(guān)的API捉偏,具體擴展如下:

GLvoid glGenVertexArraysOES(GLsizei n, GLuint *arrays)
GLvoid glBindVertexArrayOES(GLuint array);
GLvoid glDeleteVertexArraysOES(GLsizei n, const GLuint *arrays);; 
GLboolean glIsVertexArrayOES(GLuint array);

實現(xiàn)貝塞爾曲線

1、創(chuàng)建OpenGL ES3.0上下文對象泻红,由于Opengl ES3.0不是所有的設(shè)備和iOS版本都支持夭禽,因此查看支持情況請參考 OpenGL ES入門01-OpenGL ES概述 或者參見蘋果官網(wǎng) 設(shè)備特性

// 引入OpenGL ES3.0頭文件
#import <OpenGLES/ES3/gl.h> 

- (void)setupContext
{
    // 設(shè)置OpenGLES的版本為3.0
    _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
    if (!_context) {
        NSLog(@"Failed to initialize OpenGLES 3.0 context");
        exit(1);
    }
    
    // 將當(dāng)前上下文設(shè)置為我們創(chuàng)建的上下文
    if (![EAGLContext setCurrentContext:_context]) {
        NSLog(@"Failed to set current OpenGL context");
        exit(1);
    }
}

2、創(chuàng)建OpenGL ES3.0相關(guān)的著色器谊路。要想使用OpenGL ES3.0的新特性讹躯,必須要指定著色器的版本 #version 300 es 。如果不指定,則會按照2.0的版本處理潮梯,因此3.0的新特性比如in骗灶、out、layout等關(guān)鍵字會報錯秉馏。我們通過layout(location = i)指定屬性的位置矿卑,這樣我們就可以不用調(diào)用glGetAttribLocation獲取屬性的位置了。至于編譯沃饶、鏈接、創(chuàng)建著色器程序和以前2.0一樣轻黑,所以不再特別指明糊肤。

#version 300 es

layout(location = 0) in vec3 position;
layout(location = 1) in vec3 color;

out vec3 outColor;

void main()
{
    gl_Position = vec4(position, 1.0);
    outColor = color;
}
#version 300 es

precision mediump float;

in vec3 outColor;

out vec4 v_color;

void main()
{
    v_color = vec4(outColor, 1.0);
}

3、創(chuàng)建貝塞爾曲線定點氓鄙。我們通過指定一個控制點和另外兩個頂點便可以通過曲線方程創(chuàng)建貝塞爾曲線(曲線方程見之前的文章 理解與運用貝塞爾曲線 )馆揉。我們再次將t分為100份,就可以創(chuàng)建100個頂點數(shù)據(jù)抖拦,然后通過線段代表曲線的近似方式便可以畫出貝塞爾曲線升酣。

- (void)setupVertexData
{
    CGPoint p1 = CGPointMake(-0.8, 0);
    CGPoint p2 = CGPointMake(0.8, 0.2);
    CGPoint control = CGPointMake(0, -0.9);
    CGFloat deltaT = 0.01;
    
    _vertCount = 1.0/deltaT;
    _vertext = (Vertex *)malloc(sizeof(Vertex) * _vertCount);
    
    // t的范圍[0,1]
    for (int i = 0; i < _vertCount; i++) {
        float t = i * deltaT;
        
        // 二次方計算公式
        float cx = (1-t)*(1-t)*p1.x + 2*t*(1-t)*control.x + t*t*p2.x;
        float cy = (1-t)*(1-t)*p1.y + 2*t*(1-t)*control.y + t*t*p2.y;
        _vertext[i] = (Vertex){cx, cy, 0.0, 1.0, 0.0, 0.0};
        
        printf("%f, %f\n",cx, cy);
    }
}

4、創(chuàng)建頂點緩存對象VBO态罪,在此通過GLUtil封裝了一下VBO的創(chuàng)建噩茄。

GLuint createVBO(GLenum target, int usage, int datSize, void *data)
{
    GLuint vbo;
    glGenBuffers(1, &vbo);
    glBindBuffer(target, vbo);
    glBufferData(target, datSize, data, usage);
    return vbo;
}

5、創(chuàng)建頂點數(shù)組對象VAO复颈。通過VAO容易我們包裹了VBO和數(shù)組傳遞等操作绩聘,使用的時候只要激活當(dāng)前的VAO便可以完成繪制,加快了繪制效率耗啦。

- (void)setupVAO
{
    glGenVertexArrays(1, &_vao);
    glBindVertexArray(_vao);
    
    // VBO
    GLuint vbo = createVBO(GL_ARRAY_BUFFER, GL_STATIC_DRAW, sizeof(Vertex) * (_vertCount + 1), _vertext);
    
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), NULL);
    
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), NULL+sizeof(GLfloat)*3);
    
    glBindVertexArray(0);
}

6凿菩、繪制。只需要通過 glBindVertexArray 啟用創(chuàng)建VAO便可以完成繪制帜讲。

- (void)render
{
    glClearColor(1.0, 1.0, 0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glLineWidth(2.0);
    
    glViewport(0, 0, self.frame.size.width, self.frame.size.height);
    
    // VAO
    glBindVertexArray(_vao);
    
    glDrawArrays(GL_LINE_STRIP, 0, _vertCount);
    
    //將指定 renderbuffer 呈現(xiàn)在屏幕上衅谷,在這里我們指定的是前面已經(jīng)綁定為當(dāng)前 renderbuffer 的那個,在 renderbuffer 可以被呈現(xiàn)之前似将,必須調(diào)用renderbufferStorage:fromDrawable: 為之分配存儲空間获黔。
    [_context presentRenderbuffer:GL_RENDERBUFFER];
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市玩郊,隨后出現(xiàn)的幾起案子肢执,更是在濱河造成了極大的恐慌,老刑警劉巖译红,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件预茄,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機耻陕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門拙徽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人诗宣,你說我怎么就攤上這事膘怕。” “怎么了召庞?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵岛心,是天一觀的道長。 經(jīng)常有香客問我篮灼,道長忘古,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任诅诱,我火速辦了婚禮髓堪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘娘荡。我一直安慰自己干旁,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布炮沐。 她就那樣靜靜地躺著争群,像睡著了一般。 火紅的嫁衣襯著肌膚如雪央拖。 梳的紋絲不亂的頭發(fā)上祭阀,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音鲜戒,去河邊找鬼专控。 笑死,一個胖子當(dāng)著我的面吹牛遏餐,可吹牛的內(nèi)容都是我干的伦腐。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼失都,長吁一口氣:“原來是場噩夢啊……” “哼柏蘑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起粹庞,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤咳焚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后庞溜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體革半,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了又官。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片延刘。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖六敬,靈堂內(nèi)的尸體忽然破棺而出碘赖,到底是詐尸還是另有隱情,我是刑警寧澤外构,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布普泡,位于F島的核電站,受9級特大地震影響审编,放射性物質(zhì)發(fā)生泄漏劫哼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一割笙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧眯亦,春花似錦伤溉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至宫静,卻和暖如春走净,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背孤里。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工伏伯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人捌袜。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓说搅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親虏等。 傳聞我的和親對象是個殘疾皇子弄唧,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

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