2012年6月25日 星期一

OpenGL ES 2.0 with GLKit Part 2 - 1

since: 2012/06/25
update: 2012/06/25


reference:
1. Beginning OpenGL ES 2.0 with GLKit Part 2 | Ray Wenderlich
2. I touchs: OpenGL ES 2.0 with GLKit Part 1 - 2

GLKBaseEffect 介紹

A. 建立簡單的正方形頂點資料
     1. 說明:
         a. 正方形的頂點將被設置如下:
             V0: 座標(1, -1), 顏色:
             V1: 座標(1, 1), 顏色:
             V2: 座標(-1, 1), 顏色:
             V3: 座標(-1, -1), 顏色:


         b. 在 OpenGL ES 中, 只能使用三角形來繪製幾何圖形, 所以我們可以利用
              二個三角形來產生正方形, 如上圖所示: 一個三角形使用頂點 V0, V1, V2;
              另一個三角形使用頂點 V2, V3, V0.
              (說明: 你可以將頂點資料組成任何產生三角形的方式)

     2. 開啟 HelloGLKitViewController.m 檔案, 修改如下:
#import "HelloGLKitViewController.h"


///////////////////////////////////////////////////////
//@start: add for vertex data */

// 用來儲存每個頂點的資訊: 位置(x,y,z), 顏色(r,g,b,a)
typedef struct {
    float Position[3];
    float Color[4];
} Vertex;

// 所有個別頂點的資訊:
// {位置1, 顏色1}, {位置2, 顏色2}, {位置3, 顏色3}, {位置4, 顏色4}
const Vertex Vertices[] = {
    {{1, -1, 0}, {1, 0, 0, 1}},
    {{1, 1, 0}, {0, 1, 0, 1}},
    {{-1, 1, 0}, {0, 0, 1, 1}},
    {{-1, -1, 0}, {0, 0, 0, 1}}
};

// 產生三角形的頂點索引:
//
// 每三個頂點組成一個三角形:
// 第一個三角形: 由頂點索引為 0, 1 與 2 所組成
// 第二個三角形: 由頂點索引為 2, 3 與 0 所組成
const GLubyte Indices[] = {
    0, 1, 2,
    2, 3, 0
};

//@ end: add for vertex data
///////////////////////////////////////////////////////
....

----------------------------------------------------------------------------------

B. 建立 Vertex Buffer Objects

     1. 說明:
         a. 要將頂點資料送至 OpenGL, 最佳方式是經由頂點緩衝區物件
              (Vertex Buffer Objects).

         b. 根本上來說, Vertex Buffer Objects 是一種 OpenGL 物件, 用來將頂點資料
              儲存到緩衝區裡.

         c. 有二種類型的 vertex buffer objects, 一種用來保存(追蹤)每個頂點的資料
             (像之前的 Vertices 陣列); 另一種用來保存(追蹤)建立三角形的頂點索引
             (像之前的 Indices 陣列).

     2. 開啟 HelloGLKitViewController.h 檔案, 修改如下:
#import <GLKit/GLKit.h>

@interface HelloGLKitViewController : GLKViewController
{
}

//@add
- (void)setupGL;
- (void)tearDownGL;

@end

     3. 開啟 HelloGLKitViewController.m 檔案, 修改如下:
....
// step 1:
@interface HelloGLKitViewController ()
{
    //@add
    float _curRed;
    BOOL _increasing;
    GLuint _vertexBuffer;
    GLuint _indexBuffer;
}

....
// step 2:
//@add
- (void)setupGL
{
    // Set the current OpenGL context to the current context.
    [EAGLContext setCurrentContext:self.context];
   
    // Create a new Vertex Buffer object
    glGenBuffers(1, &_vertexBuffer);
   
    // Bind vertexBuffer to GL_ARRAY_BUFFER  
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
   
    // send the data over to OpenGL-land.
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
   
    glGenBuffers(1, &_indexBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
}

....
// step 3:
//@add: delete the vertex and index buffers:
- (void)tearDownGL
{
    [EAGLContext setCurrentContext:self.context];
   
    glDeleteBuffers(1, &_vertexBuffer);
    glDeleteBuffers(1, &_indexBuffer);
}

....
// step 4:
- (void)viewDidLoad
{
....
    //@add
    [self setupGL];
}

....
// step 5:
- (void)viewDidUnload
{
    [super viewDidUnload];
    //add
    [self tearDownGL];
    ....
}

....

----------------------------------------------------------------------------------

C. GLKBaseEffect 介紹

      1. 說明:
          a. 在 OpenGL ES 2.0 中, 要在場景繪製出任何的幾何圖形, 必須要建立二個
              稱為 shader 的微小程式.
              註: shader 常翻譯為著色器, 對 Fragment(像素/片段) shader 而言還算吻合;
                    但是對於主要處理頂點位置的 vertex(頂點) shader 就不貼切了.

          b. Shaders 以類似 C 語言的語法被寫成, 稱作 GLSL(OpenGL Shading Language),
              有二種基本類型的 shaders: Vertex shaderFragment shader.

          c. Vertex shader:(頂點著色器)
              在場景中的每個頂點都會呼叫一次 vertex shader 這個小程式. Vertex shader
              的工作是去執行某些計算, 例如: 光源位置, 幾何轉換(位移, 旋轉, 縮放)等,
              最後會算出每個頂點最終的位置, 並且傳遞一些資料給 fragment shader.

          d. Fragment shader:(像素著色器)
              同樣地, 在場景中的每個像素都會呼叫一次 fragment shader 這個小程式.
              Fragment shader 最主要的工作是設定每個像素最終的顏色.


          e. GLKBaseEffect 是一個輔助類別, 它為你實作了一些常用的 shaders.
              GLKBaseEffect 的目的是: 提供大部份在 OpenGL ES 1.0 中可用的功能,
              使 App 較容易從 OpenGL ES 1.0 轉成 OpenGL ES 2.0.

----------------------------------------------------------------------------------

D. GLKBaseEffect 的使用步驟
      1. 建立一個 GLKBaseEffect
          通常, 當你建立 OpenGL context 時, 就會建立其中一個 GLKBaseEffect. 你能夠
          (並且應該) 對不同的幾何圖形再使用相同的 GLKBaseEffect, 並且只需重新設定
          屬性. 在場景的背後, GLKBaseEffect 只會散佈對 shaders 有所改變的那些屬性.

      2. 設定 GLKBaseEffect 屬性
          你可以設定: 光源, 轉換(位移, 旋轉, 縮放), 以及其它 GLKBaseEffect 的 shaders
          會用來繪製幾何圖形的屬性.

      3. 在 GLKBaseEffect 上呼叫 prepareToDraw
          任何時候, 你在 GLKBaseEffect 上更改一個屬性, 你需要先呼叫 prepareToDraw
          來讓 shaders 能正確地設定. 這也會賦予 GKBaseEffect 的 shaders 成為目前的
          shader program.

      4. 啟用 "預先定義好的" 的屬性
          通常, 當你建好你自己的 shaders, 它們帶有稱為 attributes參數, 並且你可以
          在 App 中寫程式碼來取得 attributes 參數的 IDs. 對 GLKBaseEffect 內建
          shaders 而言, 那些 attributes 參數是已經 "定義好的" 常數, 如: 
          GLKVertexAttribPositionGLKVertexAttribColor. 所以你需要啟用任何想要
          傳遞到 shaders 裡的參數, 並且將這些參數參照到資料.          

      5. 繪製你的幾何圖形
          一旦你都設定好之後, 就可以使用標準的 OpenGL 繪圖指令, 如: glDrawArrays
          或 glDrawElements, 它就會依照你設定的效果來繪製.  

----------------------------------------------------------------------------------

E. 備註:
      1. GLKBaseEffect 最棒的一件事就是: 如果你使用它們, 你就不需要寫任何的
          shaders. 當然, 如果你想要也可以用混搭的方式: 用 GLKBaseEffect 來繪製
          某些圖形; 再用你自己寫的 shaders 繪製另外的圖形. 如果你看看 OpenGL
          的樣板專案, 就會看到這樣的例子.

     2. 在這篇教學文章中, 會將焦點放在只使用 GLKBaseEffect, 因為主要的目的是
          讓你能夠儘快的使用新的 GLKit 功能, 它是相當容易的.

沒有留言:

張貼留言

注意:只有此網誌的成員可以留言。