OpenGL ES學(xué)習(xí)筆記(二):畫一個三角形

示例最終效果

這篇筆記的關(guān)鍵在于對OpenGL ES繪圖7個步驟中的函數(shù)各個參數(shù)的的解讀,筆者之前看別人的文章被這些函數(shù)的參數(shù)弄的暈頭轉(zhuǎn)向,看了這本書之后終于理解透徹。


準(zhǔn)備

  1. 首先復(fù)習(xí)一下為緩存提供數(shù)據(jù)的7個步驟,可以在第一篇筆記中查看,這里不再贅述。
  2. iOS中使用OpenGL ES的框架為GLKit,Demo中會使用UIViewController的子類GLKViewController作為主控制器,將控制器的view轉(zhuǎn)換為GLKView,這樣可以省去設(shè)置GLKView代理等操作。

需要注意本例中直接使用默認(rèn)新建的項目,需要在storyboard中修改ViewController中View的類型為GLKView,需要在ViewController.h中把父類改為GLKViewController。

  1. 示例概要:
    • 準(zhǔn)備三角形頂點數(shù)據(jù)數(shù)組
    • 設(shè)置GLKView的上下文為當(dāng)前的上下文
    • 設(shè)置著色器屬性
    • 申請、綁定、緩存頂點數(shù)據(jù)
    • 在代理方法中,準(zhǔn)備繪圖
      • 著色器準(zhǔn)備
      • 清理
      • 啟用緩存頂點數(shù)據(jù)、設(shè)置指針、繪圖
    • dealloc方法中刪除緩存數(shù)據(jù)

示例解說

一、準(zhǔn)備頂點數(shù)據(jù)數(shù)組
  • 聲明一個結(jié)構(gòu)體保存一個頂點的數(shù)據(jù)
  • 創(chuàng)建一個C數(shù)組保存三角形的3個頂點

/** 保存每個頂點的數(shù)據(jù) */
typedef struct vector {
    GLKVector3 positionCoords;
}SceneVertex;

/** 保存三角形3個頂點的數(shù)據(jù) */
static const SceneVertex vertices[] = {
    {{-0.5, -0.5, 0}},
    {{ 0.5, -0.5, 0}},
    {{-0.5,  0.5, 0}}
};

二、設(shè)置當(dāng)前的上下文為view的上下文
/** 強轉(zhuǎn)view為GLKView,需要在storyboard中也要修改 */
GLKView *view = (GLKView *)self.view;

/** 斷言,判斷view的類型 */
NSAssert([view isMemberOfClass:[GLKView class]], @"View controller's view is not a GLKView");
    
/** 創(chuàng)建一個OpenGL ES 2.0的上下文給view */
view.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    
/** 將view的上下文設(shè)置為當(dāng)前的上下文 */
[EAGLContext setCurrentContext:view.context];
三、設(shè)置著色器,三角顏色及背景色
/** 為OpenGL ES 2.0創(chuàng)建一個默認(rèn)的基本效果并提供給片元著色器程序,用于之后的繪圖渲染 */
_baseEffect = [[GLKBaseEffect alloc] init];
_baseEffect.useConstantColor = GL_TRUE;
_baseEffect.constantColor = GLKVector4Make(200.0, /** 紅 */
                                           0.0,   /** 綠 */
                                           0.0,   /** 藍 */
                                           1.f);  /** alpha */

/** 設(shè)置背景色,存儲到當(dāng)前的上下文中 */
glClearColor(1.0, 1.0, 1.0, 1.0);
四、申請、綁定、緩存

函數(shù)的參數(shù)說明已經(jīng)在注釋中寫的非常詳細了!

/** 申請、綁定并初始化一塊緩存,將繪圖信息保存到GPU的當(dāng)中 */
/** ①申請 */
glGenBuffers(1,                 /** 指定要生成的緩存標(biāo)識符的數(shù)量 */
             &vertexBufferID);  /** 指針:緩存標(biāo)識符的地址 */
/** ②綁定 */
glBindBuffer(GL_ARRAY_BUFFER,   /** 綁定什么類型的緩存:頂點屬性數(shù)組 */
             vertexBufferID);   /** 需要綁定的緩存的標(biāo)識符(標(biāo)識符為0表示沒有緩存,就不會綁定數(shù)據(jù)) */
/** ③緩存數(shù)據(jù) */
glBufferData(GL_ARRAY_BUFFER,   /** 初始化緩存信息 */
             sizeof(vertices),  /** 緩存需要拷貝的大小 */
             vertices,          /** 需要拷貝的數(shù)據(jù):拷貝數(shù)據(jù)的地址 */
             GL_STATIC_DRAW);   /** 提示:告訴上下文緩存適合放到GPU內(nèi)存中,因為數(shù)據(jù)很少被更改,可以幫助OpenGL ES優(yōu)化內(nèi)存 */

五、開始繪圖
  • 當(dāng)GLKView需要重新繪制時就會調(diào)用代理方法glkView:drawInRect:

  • 在代理方法內(nèi),開始準(zhǔn)備繪圖工作

    /** 準(zhǔn)備繪制 */
    [_baseEffect prepareToDraw];
    
    /** 清理之前的繪圖 */
    glClear(GL_COLOR_BUFFER_BIT);
    
  • 啟用頂點數(shù)據(jù)、設(shè)置指針、開始繪圖

    /** ④啟用頂點數(shù)據(jù) */
    glEnableVertexAttribArray(GLKVertexAttribPosition);
    
    /** ⑥設(shè)置指針:目的在于告訴OpenGL ES頂點數(shù)據(jù)在哪里以及解釋每個頂點保存的數(shù)據(jù) */
    glVertexAttribPointer(GLKVertexAttribPosition, /** 頂點數(shù)據(jù) */
                        3,                       /** 每個頂點包含3個數(shù)據(jù) */
                        GL_FLOAT,                /** 頂點數(shù)據(jù)類型 */
                        GL_FALSE,                /** 固定點數(shù)據(jù)是否歸一化或直接轉(zhuǎn)固定值:不轉(zhuǎn)換,直接使用float類型數(shù)據(jù),可以幫助OpenGL ES優(yōu)化內(nèi)存 */
                        sizeof(SceneVertex),     /** 步幅:從一個頂點到另一個需要跨過多少字節(jié),取單個頂點大小 */
                        NULL);                   /** 告訴OpenGL ES可以從當(dāng)前綁定的頂點緩存的開始位置訪問頂點數(shù)據(jù) */
    
    glDrawArrays(GL_TRIANGLES,  /** 告訴GPU怎樣渲染緩存內(nèi)的頂點數(shù)據(jù):渲染三角形 */
               0,             /** 第一個需要渲染的頂點位置 */
               3);            /** 渲染的頂點數(shù)量 */
    
六、最后的清理工作

在dealloc方法中清理緩存

/** 如果有緩存的情況下 */
if (vertexBufferID != 0) {
        
    /** ⑦刪除緩沖區(qū)數(shù)據(jù) */
    glDeleteBuffers(1, &vertexBufferID);
        
    /** 將標(biāo)識符設(shè)置為0 */
    vertexBufferID = 0;
}
    
/** 將當(dāng)前上下文設(shè)置nil */
[EAGLContext setCurrentContext:nil];

小結(jié)

  • 示例算是OpenGL ES中最簡單的,只是為了熟悉7個步驟而生,旨在熟悉基本的流程、函數(shù)及函數(shù)的各個參數(shù)。
  • 代碼會在后續(xù)統(tǒng)一上傳到github,其實基本上都貼出來了,當(dāng)然有需要的可以自行下載。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容