2012年6月21日 星期四

OpenGL ES 2.0 Tutorial Part 2 - 2

since: 2012/06/21
update: 2012/06/21


reference:
1. OpenGL ES 2.0 for iPhone Tutorial Part 2: Textures | Ray Wenderlich
2. I touchs: OpenGL ES 2.0 Tutorial Part 2 - 1

紋理貼圖之二

A. 修正被伸展的效果
      1. 說明:
          a. 造成伸展效果的原因是: 我們目前只是為每個頂點設定一個紋理座標, 並且
              重覆使用這些頂點.

          b. 例如, 我們把立方體的前面左下角對應到 (0, 0). 但是在左邊那一面, 相同的
              頂點
卻變成了在右下方, 所以如果此時對應到的紋理座標同樣為 (0, 0) 就
              沒有意義了, 它應該是 (1, 0).  

          c. 在 OpenGL 裡, 你不能把頂點只是當成頂點座標, 它是由以下所組合而成的
              獨一無二的點: 座標, 顏色, 紋理座標以及任何在你的結構中所擁有的其它元素.

***************************************************************

      2. 開啓 OpenGLView.m 檔案, 修改如下:
//setp01
#import "OpenGLView.h"

//@add for projection
#import "CC3GLMatrix.h"

//@add
#define TEX_COORD_MAX   1
....

//setp02
/*
const Vertex Vertices[] = {
    {{1, -1, 0}, {1, 0, 0, 1}, {1, 0}},
    {{1, 1, 0}, {1, 0, 0, 1}, {1, 1}},
    {{-1, 1, 0}, {0, 1, 0, 1}, {0, 1}},
    {{-1, -1, 0}, {0, 1, 0, 1}, {0, 0}},
    {{1, -1, -1}, {1, 0, 0, 1}, {1, 0}},
    {{1, 1, -1}, {1, 0, 0, 1}, {1, 1}},
    {{-1, 1, -1}, {0, 1, 0, 1}, {0, 1}},
    {{-1, -1, -1}, {0, 1, 0, 1}, {0, 0}}
};
*/

//@update
// 要確保紋理座標能正確的對應:
// 為每個面建立各自不同的: 頂點, 顏色與紋理座標
const Vertex Vertices[] = {
    // Front
    {{1, -1, 0}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}},
    {{1, 1, 0}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}},
    {{-1, 1, 0}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}},
    {{-1, -1, 0}, {0, 0, 0, 1}, {0, 0}},
    // Back
    {{1, 1, -2}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}},
    {{-1, -1, -2}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}},
    {{1, -1, -2}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}},
    {{-1, 1, -2}, {0, 0, 0, 1}, {0, 0}},
    // Left
    {{-1, -1, 0}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}},
    {{-1, 1, 0}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}},
    {{-1, 1, -2}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}},
    {{-1, -1, -2}, {0, 0, 0, 1}, {0, 0}},
    // Right
    {{1, -1, -2}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}},
    {{1, 1, -2}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}},
    {{1, 1, 0}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}},
    {{1, -1, 0}, {0, 0, 0, 1}, {0, 0}},
    // Top
    {{1, 1, 0}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}},
    {{1, 1, -2}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}},
    {{-1, 1, -2}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}},
    {{-1, 1, 0}, {0, 0, 0, 1}, {0, 0}},
    // Bottom
    {{1, -1, -2}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}},
    {{1, -1, 0}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}},
    {{-1, -1, 0}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}},
    {{-1, -1, -2}, {0, 0, 0, 1}, {0, 0}}
};
....

//setp03
/*
const GLubyte Indices[] = {
    // Front
    0, 1, 2,
    2, 3, 0,
    // Back
    4, 6, 5,
    4, 7, 6,
    // Left
    2, 7, 3,
    7, 6, 2,
    // Right
    0, 4, 1,
    4, 1, 5,
    // Top
    6, 2, 1,
    1, 6, 5,
    // Bottom
    0, 3, 7,
    0, 7, 4   
};
*/

//@update
const GLubyte Indices[] = {
    // Front
    0, 1, 2,
    2, 3, 0,
    // Back
    4, 5, 6,
    4, 5, 7,
    // Left
    8, 9, 10,
    10, 11, 8,
    // Right
    12, 13, 14,
    14, 15, 12,
    // Top
    16, 17, 18,
    18, 19, 16,
    // Bottom
    20, 21, 22,
    22, 23, 20
};
....

***************************************************************

      3. 編譯並執行:

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

B. 重複貼圖
      1. 說明:
          在 OpenGL 裡, 如果你喜歡的話, 可以很容易地在物體表面上建立重複
          紋理貼圖. 我們所要使用的地磚紋理, 最好是無縫的紋理.

      2. 開啓 OpenGLView.m 檔案, 修改如下:
....
//@add
//#define TEX_COORD_MAX   1
#define TEX_COORD_MAX   4
....

        說明: 現在我們讓立方體的每個面從左下角 (0, 0) 到右上角 (4, 4) 都對應到
                   紋理貼圖上.

      3. 編譯並執行:
          可以看到沿著立方體表面的重複紋理.

          說明: 能夠這樣自動完成的原因是 GL_TEXTURE_WRAP_S
                     GL_TEXTURE_WRAP_T 的預設值為 GL_REPEAT. 如果不想讓紋理
                     如此重復的話, 你可以利用 glTexParameteri覆寫預設的值.

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

C. 加入花樣
      1. 開啓 OpenGLView.h 檔案, 修改如下:
....
@interface OpenGLView : UIView
{
.... 
    //@add
    //
    // 我們分別需要二個 vertex / index buffers
    // 一個給立方體, 另一個給擁有 "魚骨花樣" 的那一個表面
    GLuint _vertexBuffer;
    GLuint _indexBuffer;
    GLuint _vertexBuffer2;
    GLuint _indexBuffer2;
}
....

      2. 開啓 OpenGLView.m 檔案, 修改如下:
....
// step01
//@add: 為要繪製魚骨紋理的矩形定義一組新的頂點集合
//
// 我們將它設置的比前方表面還要小一些, 並且將 Z 座標的值稍微調高一些, 讓它浮現.
// 不然的話, 在作深度測試時就會被摒棄掉.

const Vertex Vertices2[] = {
    {{0.5, -0.5, 0.01}, {1, 1, 1, 1}, {1, 1}},
    {{0.5, 0.5, 0.01}, {1, 1, 1, 1}, {1, 0}},
    {{-0.5, 0.5, 0.01}, {1, 1, 1, 1}, {0, 0}},
    {{-0.5, -0.5, 0.01}, {1, 1, 1, 1}, {0, 1}},
};

//@add
const GLubyte Indices2[] = {
    1, 0, 2, 3
};

@implementation OpenGLView
....

// step02
- (void)setupVBOs
{
    /*
    GLuint vertexBuffer;
    // 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);
   
   
    GLuint indexBuffer;
    // Create a new Index Buffer object
    glGenBuffers(1, &indexBuffer);
   
    // Bind "indexBuffer" to GL_ELEMENT_ARRAY_BUFFER
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
   
    // Send the data over to OpenGL-land
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
    */
   
    // 原本的頂點 Buffer
    glGenBuffers(1, &_vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
   
    //原本的索引 Buffer
    glGenBuffers(1, &_indexBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
   
    // 包含魚骨的矩形之頂點 Buffer
    glGenBuffers(1, &_vertexBuffer2);
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer2);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices2), Vertices2, GL_STATIC_DRAW);
   
    // 包含魚骨的矩形之索引 Buffer
    glGenBuffers(1, &_indexBuffer2);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer2);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices2), Indices2, GL_STATIC_DRAW);
}
....

// step03
....
- (void)render:(CADisplayLink *)displayLink
{
....
    glViewport(0, 0, self.frame.size.width, self.frame.size.height);
   
    //@add: right after call to glViewport
    // 繪製紋理前先將立方體的 vertex/index buffer 綁定
    // (不能夠再假設它已設定好了)
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
....
}
....

// step04
....
- (void)render:(CADisplayLink *)displayLink
{
....
    //@add: right before [_context presentRenderbuffer:]
    //
    // 綁定包含魚骨的矩形之 vertex/index buffers
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer2);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer2);
   
    // 載入魚骨的紋理
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, _fishTexture);
    glUniform1i(_textureUniform, 0);
   
    glUniformMatrix4fv(_modelViewUniform, 1, 0, modelView.glMatrix);
   
    // 設定屬性
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 3));
    glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 7));
   
    // 使用 GL_TRIANGLE_STRIP 來產生三角形, 可降低 index buffer 的大小.
    glDrawElements(GL_TRIANGLE_STRIP, sizeof(Indices2)/sizeof(Indices2[0]), GL_UNSIGNED_BYTE, 0);
       
   
    // Present the render/color buffer to the UIView's layer!
    [_context presentRenderbuffer:GL_RENDERBUFFER];
}
....

      3. 編譯並執行:

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

D. 啟用渲染效果
      1. 開啓 OpenGLView.m 檔案, 修改如下:
....
- (void)render:(CADisplayLink *)displayLink
{
    //@add for blending
    //
    // 設定 blending 的規則
    //
    // GL_ONE:(for the source) 渲染所有來源圖片的像素.
    //
    // GL_ONE_MINUS_SRC_ALPHA:(for the destination)
    // 渲染所有目標圖片資料, 除了已設置的來源圖片.

    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
   
    // 啟用渲染
    glEnable(GL_BLEND);
....
}

    備註: 關於渲染的模式, 可參考: 這篇教學文章.

      2. 編譯並執行:

沒有留言:

張貼留言

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