<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      [OpenGL ES 06]使用VBO:頂點(diǎn)緩存

      [OpenGL ES 06]使用VBO:頂點(diǎn)緩存

      羅朝輝 (http://www.rzrgm.cn/kesalin/)

      本文遵循“署名-非商業(yè)用途-保持一致”創(chuàng)作公用協(xié)議

       

      這是《OpenGL ES 教程》的第六篇,前五篇請(qǐng)參考如下鏈接:

      [OpenGL ES 01]iOS上OpenGL ES之初體驗(yàn)
      [OpenGL ES 02]OpenGL ES渲染管線與著色器
      [OpenGL ES 03]3D變換:模型,視圖,投影與Viewport
      [OpenGL ES 04]3D變換實(shí)踐篇:平移,旋轉(zhuǎn),縮放
      [OpenGL ES 05]相對(duì)空間變換及顏色

       

      一,VBO簡(jiǎn)介

      在前面幾篇的示例中,都是通過類似如下代碼直接從 CPU 主存中傳遞頂點(diǎn)數(shù)據(jù)到 GPU 中去進(jìn)行運(yùn)算與渲染的。

          glVertexAttrib4f(_colorSlot, color[0], color[1], color[2], color[3]);
          glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices );
          glEnableVertexAttribArray(_positionSlot);
          
          glDrawElements(GL_LINES, sizeof(indices)/sizeof(GLubyte), GL_UNSIGNED_BYTE, indices);

      在上面的代碼中 vertices 和 indices 都是在主存中分配的內(nèi)存空間,當(dāng)需要進(jìn)行渲染時(shí),這些數(shù)據(jù)便通過 glDrawElements 或 glDrawArrays 從 CPU 主存中拷貝到 GPU 中去進(jìn)行運(yùn)算與渲染。這種做法需要頻繁地在 CPU 與 GPU 之間傳遞數(shù)據(jù),效率低下,因此出現(xiàn)了 VBO (Vertex Buffer object),即頂點(diǎn)緩存,它直接在 GPU 中開辟一個(gè)緩存區(qū)域來存儲(chǔ)頂點(diǎn)數(shù)據(jù),因?yàn)樗怯脕砭彺鎯?chǔ)頂點(diǎn)數(shù)據(jù),因此被稱之為頂點(diǎn)緩存。我們只會(huì)在初始化緩沖區(qū),以及在頂點(diǎn)數(shù)據(jù)有變化時(shí)才需要對(duì)該緩沖區(qū)進(jìn)行寫操作。使用頂點(diǎn)緩存能夠大大較少了CPU-GPU 之間的數(shù)據(jù)拷貝開銷,因此顯著地提升了程序運(yùn)行的效率。

      今天我們就能學(xué)習(xí) VBO 在 OpenGL ES 中的運(yùn)用,示例程序演示了六種編程實(shí)現(xiàn)的物體,本文源碼:點(diǎn)此查看,其運(yùn)行效果如下:

       

      二,API介紹

      1,總覽

      OpenGL ES 中通過如下函數(shù)來實(shí)現(xiàn) VBO:

      頂點(diǎn)緩存對(duì)象 API
      glGenBuffers 創(chuàng)建頂點(diǎn)緩存對(duì)象
      glBindBuffer 將頂點(diǎn)緩存對(duì)象設(shè)置為當(dāng)前數(shù)組緩存對(duì)象(array buffer object)或當(dāng)前元素緩存對(duì)象(element buffer object)
      glBufferData 為頂點(diǎn)緩存對(duì)象申請(qǐng)內(nèi)存空間,并進(jìn)行初始化(視傳入的參數(shù)而定)
      glBufferSubData 初始化或更新頂點(diǎn)緩存對(duì)象
      glDeleteBuffers 刪除頂點(diǎn)緩存對(duì)象



       



       

      2,創(chuàng)建頂點(diǎn)緩存對(duì)象

      void glGenBuffers (GLsizei n, GLuint* buffers);

      參數(shù) n : 表示需要?jiǎng)?chuàng)建頂點(diǎn)緩存對(duì)象的個(gè)數(shù);
      參數(shù) buffers :用于存儲(chǔ)創(chuàng)建好的頂點(diǎn)緩存對(duì)象句柄;

      同第一篇文章《[OpenGL ES 01]OpenGL ES之初體驗(yàn)》中的講的 render buffer 對(duì)象句柄一樣,在這里,頂點(diǎn)緩存對(duì)象句柄始終是大于 0 的正整數(shù),0 是 OpenGL ES 保留。該函數(shù)能夠一次產(chǎn)生多個(gè)頂點(diǎn)緩存對(duì)象。

      3,將頂點(diǎn)緩存對(duì)象設(shè)置為(或曰綁定到)當(dāng)前數(shù)組緩存對(duì)象或元素緩存對(duì)象

      void glBindBuffer (GLenum target, GLuint buffer);

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

      4,為頂點(diǎn)緩存對(duì)象分配空間

      void glBufferData (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);

      參數(shù) target:與 glBindBuffer 中的參數(shù) target 相同;
      參數(shù) size :指定頂點(diǎn)緩存區(qū)的大小,以字節(jié)為單位計(jì)數(shù);
      data :用于初始化頂點(diǎn)緩存區(qū)的數(shù)據(jù),可以為 NULL,表示只分配空間,之后再由 glBufferSubData 進(jìn)行初始化;
      usage :表示該緩存區(qū)域?qū)?huì)被如何使用,它的主要目的是用于提示OpenGL該對(duì)該緩存區(qū)域做何種程度的優(yōu)化。其參數(shù)為以下三個(gè)之一:
      GL_STATIC_DRAW:表示該緩存區(qū)不會(huì)被修改;
      GL_DyNAMIC_DRAW:表示該緩存區(qū)會(huì)被周期性更改;
      GL_STREAM_DRAW:表示該緩存區(qū)會(huì)被頻繁更改;

      如果頂點(diǎn)數(shù)據(jù)一經(jīng)初始化就不會(huì)被修改,那么就應(yīng)該盡量使用 GL_STATIC_DRAW,這樣能獲得更好的性能。

      5,更新頂點(diǎn)緩沖區(qū)數(shù)據(jù)

      void glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);

      參數(shù) :offset 表示需要更新的數(shù)據(jù)的起始偏移量;
      參數(shù) :size 表示需要更新的數(shù)據(jù)的個(gè)數(shù),也是以字節(jié)為計(jì)數(shù)單位;
      data :用于更新的數(shù)據(jù);

      6,釋放頂點(diǎn)緩存

      void glDeleteBuffers (GLsizei n, const GLuint* buffers);

      參數(shù)與 glGenBuffers 類似,就不再累述,該函數(shù)用于刪除頂點(diǎn)緩存對(duì)象,釋放頂點(diǎn)緩存。

       

      三,多面手:glVertexAttribPointer 和 glDrawElements

      在介紹如何使用 VBO 進(jìn)行渲染之前,我們先來回顧一下之前使用頂點(diǎn)數(shù)組進(jìn)行渲染用到的函數(shù):

      void glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);

      參數(shù) index :為頂點(diǎn)數(shù)據(jù)(如頂點(diǎn),顏色,法線,紋理或點(diǎn)精靈大小)在著色器程序中的槽位;
      參數(shù) size :指定每一種數(shù)據(jù)的組成大小,比如頂點(diǎn)由 x, y, z 3個(gè)組成部分,紋理由 u, v 2個(gè)組成部分;
      參數(shù) type :表示每一個(gè)組成部分的數(shù)據(jù)格式;
      參數(shù) normalized : 表示當(dāng)數(shù)據(jù)為法線數(shù)據(jù)時(shí),是否需要將法線規(guī)范化為單位長(zhǎng)度,對(duì)于其他頂點(diǎn)數(shù)據(jù)設(shè)置為 GL_FALSE 即可。如果法線向量已經(jīng)為單位長(zhǎng)度設(shè)置為 GL_FALSE 即可,這樣可免去不必要的計(jì)算,提升效率;
      stride : 表示上一個(gè)數(shù)據(jù)到下一個(gè)數(shù)據(jù)之間的間隔(同樣是以字節(jié)為單位),OpenGL ES根據(jù)該間隔來從由多個(gè)頂點(diǎn)數(shù)據(jù)混合而成的數(shù)據(jù)塊中跳躍地讀取相應(yīng)的頂點(diǎn)數(shù)據(jù);
      ptr :值得注意,這個(gè)參數(shù)是個(gè)多面手。如果沒有使用 VBO,它指向 CPU 內(nèi)存中的頂點(diǎn)數(shù)據(jù)數(shù)組;如果使用 VBO 綁定到 GL_ARRAY_BUFFER,那么它表示該種類型頂點(diǎn)數(shù)據(jù)在頂點(diǎn)緩存中的起始偏移量。

      那 GL_ELEMENT_ARRAY_BUFFER 表示的索引數(shù)據(jù)呢?那是由以下函數(shù)使用的:

      void glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);

      參數(shù) mode :表示描繪的圖元類型,如:GL_TRIANGLES,GL_LINES,GL_POINTS;
      參數(shù) count : 表示索引數(shù)據(jù)的個(gè)數(shù);
      參數(shù) type : 表示索引數(shù)據(jù)的格式,必須是無符號(hào)整形值;
      indices :這個(gè)參數(shù)也是個(gè)多面手,如果沒有使用 VBO,它指向 CPU 內(nèi)存中的索引數(shù)據(jù)數(shù)組;如果使用 VBO 綁定到 GL_ELEMENT_ARRAY_BUFFER,那么它表示索引數(shù)據(jù)在 VBO 中的偏移量。

       

      四,使用示例

      在今天的示例中,我借用《iPhone 3D Programming》中創(chuàng)建可編程3維物體的部分代碼來創(chuàng)建3維物體的頂點(diǎn)以及索引,在這里就略去這部分的介紹,有興趣研究的同學(xué)可以查看源碼。在這里就只講與頂點(diǎn)緩存相關(guān)的部分代碼。

      首先是創(chuàng)建頂點(diǎn)緩存對(duì)象,分配空間并初始化:

          // Create the VBO for the vertice.
          //
          GLuint vertexBuffer;
          glGenBuffers(1, &vertexBuffer);
          glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
          glBufferData(GL_ARRAY_BUFFER, vBufSize * sizeof(GLfloat), vbuf, GL_STATIC_DRAW);
          
          // Create the VBO for the line indice
          //
          GLuint lineIndexBuffer;
          glGenBuffers(1, &lineIndexBuffer);
          glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lineIndexBuffer);
          glBufferData(GL_ELEMENT_ARRAY_BUFFER, lineIndexCount * sizeof(GLushort), lineBuf, GL_STATIC_DRAW);
          
          // Create the VBO for the triangle indice
          //
          GLuint triangleIndexBuffer;
          glGenBuffers(1, &triangleIndexBuffer);
          glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangleIndexBuffer);
          glBufferData(GL_ELEMENT_ARRAY_BUFFER, triangleIndexCount * sizeof(GLushort), triangleBuf, GL_STATIC_DRAW);

      然后,使用 VBO 進(jìn)行渲染:

      - (void)drawSurface
      {
          if (_currentVBO == nil)
              return;
          
          glBindBuffer(GL_ARRAY_BUFFER, [_currentVBO vertexBuffer]);
          glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, [_currentVBO vertexSize] * sizeof(GLfloat), 0);
          glEnableVertexAttribArray(_positionSlot);
          
          // Draw the red triangles.
          //
          glVertexAttrib4f(_colorSlot, 1.0, 0.0, 0.0, 1.0);
          glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, [_currentVBO triangleIndexBuffer]);
          glDrawElements(GL_TRIANGLES, [_currentVBO triangleIndexCount], GL_UNSIGNED_SHORT, 0);
          
          // Draw the black lines.
          //
          glVertexAttrib4f(_colorSlot, 0.0, 0.0, 0.0, 1.0);
          glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, [_currentVBO lineIndexBuffer]);
          glDrawElements(GL_LINES, [_currentVBO lineIndexCount], GL_UNSIGNED_SHORT, 0);
          
          glDisableVertexAttribArray(_positionSlot);
      }

      由于本示例可描繪 6 個(gè)3維幾何物體,因此 _currentVBO 表示當(dāng)前描繪的幾何物體,這是一個(gè) DrawableVBO 對(duì)象。DrawableVBO 類聲明如下:

      @interface DrawableVBO : NSObject
      
      @property (nonatomic, assign) GLuint vertexBuffer;
      @property (nonatomic, assign) GLuint lineIndexBuffer;
      @property (nonatomic, assign) GLuint triangleIndexBuffer;
      @property (nonatomic, assign) int vertexSize;
      @property (nonatomic, assign) int lineIndexCount;
      @property (nonatomic, assign) int triangleIndexCount;
      
      - (void) cleanup;
      
      @end

      它包含一個(gè)用于頂點(diǎn)數(shù)據(jù)的頂點(diǎn)緩存對(duì)象 vertexBuffer 和兩個(gè)用于索引數(shù)據(jù)的頂點(diǎn)緩存對(duì)象 lineIndexBuffer 和 triangleIndexBuffer,這些對(duì)象都是通過前面的創(chuàng)建頂點(diǎn)緩存對(duì)象部分代碼生成的。vertexSize 表示頂點(diǎn)數(shù)據(jù)的大小,而 lineIndexCount 和 triangleIndexCount 表示索引數(shù)據(jù)的個(gè)數(shù)。方法 cleanup 是用于清理頂點(diǎn)緩存對(duì)象,其實(shí)現(xiàn)如下:

      - (void) cleanup
      {
          if (vertexBuffer != 0) {
              glDeleteBuffers(1, &vertexBuffer);
              vertexBuffer = 0;
          }
          
          if (lineIndexBuffer != 0) {
              glDeleteBuffers(1, &lineIndexBuffer);
              lineIndexBuffer = 0;
          }
          
          if (triangleIndexBuffer) {
              glDeleteBuffers(1, &triangleIndexBuffer);
              triangleIndexBuffer = 0;
          }
      }

       

      五,運(yùn)行效果

      本示例演示了 6 中不同形狀的可編程幾何物體,并使用 Quaternion 來響應(yīng)手指滑動(dòng)形成的旋轉(zhuǎn)操作。示例運(yùn)行效果如圖所示:

       

      六,練習(xí)作業(yè)

      在示例中,是通過編程方式來生成頂點(diǎn)數(shù)據(jù)與索引數(shù)據(jù)。那如果我想用已有頂點(diǎn)數(shù)據(jù)和索引數(shù)據(jù)來使用 VBO,那么該如何做呢?下面提供一個(gè)立方體 cube 的頂點(diǎn)數(shù)據(jù)和索引數(shù)據(jù),看聰明的你能不能修改它,加入本示例中成為第七個(gè)幾何圖形,這個(gè)作業(yè)就留個(gè)你了。

      // Cube 頂點(diǎn)數(shù)據(jù)以及索引數(shù)據(jù)
      
          const GLfloat vertices[] = {
              -1.5f, -1.5f, 1.5f, -0.577350, -0.577350, 0.577350,
              -1.5f, 1.5f, 1.5f, -0.577350, 0.577350, 0.577350,
              1.5f, 1.5f, 1.5f, 0.577350, 0.577350, 0.577350,
              1.5f, -1.5f, 1.5f, 0.577350, -0.577350, 0.577350,
              
              1.5f, -1.5f, -1.5f, 0.577350, -0.577350, -0.577350,
              1.5f, 1.5f, -1.5f, 0.577350, 0.577350, -0.577350,
              -1.5f, 1.5f, -1.5f, -0.577350, 0.577350, -0.577350,
              -1.5f, -1.5f, -1.5f, -0.577350, -0.577350, -0.577350
          };
          
          const GLushort indices[] = {
              // Front face
              3, 2, 1, 3, 1, 0,
              
              // Back face
              7, 5, 4, 7, 6, 5,
              
              // Left face
              0, 1, 7, 7, 1, 6,
              
              // Right face
              3, 4, 5, 3, 5, 2,
              
              // Up face
              1, 2, 5, 1, 5, 6,
              
              // Down face
              0, 7, 3, 3, 7, 4
          };

       

      posted @ 2012-12-20 22:32  飄飄白云  閱讀(11469)  評(píng)論(2)    收藏  舉報(bào)
      本博客遵循 Creative Commons License “署名-非商業(yè)用途-保持一致”創(chuàng)作共用協(xié)議。 與我聯(lián)系
      主站蜘蛛池模板: 亚洲精品国产av成人网| 国产sm调教折磨视频| 亚洲成av人片不卡无码手机版| 色综合久久综合久鬼色88| 青青草无码免费一二三区| 国产精品麻豆成人av网| 中文字幕乱码一区二区免费| awww在线天堂bd资源在线| 亚洲春色在线视频| 久久毛片少妇高潮| 日韩人妻熟女中文字幕a美景之屋| 东京道一本热中文字幕| 国产又色又刺激高潮视频| 阳朔县| 中文字幕有码无码AV| 亚洲+成人+国产| 亚洲中文字幕日产无码成人片| 精品久久精品久久精品九九| 一本大道久久香蕉成人网| 亚洲AV成人片不卡无码| 国产精品中文字幕综合| 成人国产精品中文字幕| 亚洲精品一二三四区| 精品无人乱码一区二区三区| 欧美大胆老熟妇乱子伦视频| 国产亚洲精品久久久久秋霞| 日本亚洲一区二区精品久久| 久久精品国产亚洲av麻| 久久精品国产再热青青青| 亚洲欧美日韩综合久久久| 久久精品伊人狠狠大香网| 亚洲人妻一区二区精品| 国产精品视频不卡一区二区| 国产永久免费高清在线| 无码人妻精品一区二区三区下载| 欧美成人无码a区视频在线观看| 国产91丝袜在线观看| 人妻精品久久无码专区涩涩| 性一交一乱一伦一| 国产无人区码一区二区| 国产一区二区午夜福利久久|