update: 2012/06/08
reference:
1. OpenGL ES 2.0 for iPhone Tutorial | Ray Wenderlich
2. I touchs: OpenGL ES 2.0 Tutorial Part 1 - 1
3. I touchs: OpenGL ES 2.0 Tutorial Part 1 - 2
4. I touchs: OpenGL ES 2.0 Tutorial Part 1 - 3
5. glVertexAttribPointer
6. glDrawElements
Creating Vertex Data
A. 為簡單的正方形建立頂點資料
1. 說明:
a. 正方形的頂點將被設置如下:
V0: 座標(1, -1), 顏色: 紅
V1: 座標(1, 1), 顏色: 綠
V2: 座標(-1, 1), 顏色: 藍
V3: 座標(-1, -1), 顏色: 黑
二個三角形來產生正方形, 如上圖所示: 一個三角形使用頂點 V0, V1, V2;
另一個三角形使用頂點 V2, V3, V0.
(說明: 你可以將頂點資料組成任何產生三角形的方式)
2. 開啟 OpenGLView.m 檔案, 修改如下:
#import "OpenGLView.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. 開啟 OpenGLView.h 檔案, 修改如下:
....
//@add
- (GLuint)compileShader:(NSString *)shaderName withType:(GLenum)shaderType;
- (void)compileShaders;
- (void)setupVBOs; // Creating Vertex Buffer Objects
@end
3. 開啟 OpenGLView.m 檔案, 修改如下:
....
//@add: Creating Vertex Buffer Objects
- (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);
}
....
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
//@add
[self setupLayer]; // Set layer to opaque(不透明)
[self setupContext]; // Create OpenGL context
[self setupRenderBuffer]; // Create a render buffer
[self setupFrameBuffer]; // Create a frame buffer
//@add
[self compileShaders];
[self setupVBOs]; // Creating Vertex Buffer Objects
[self render]; // render something
}
return self;
}
....
----------------------------------------------------------------------------------
C. 更新繪圖的程式碼
1. 開啟 OpenGLView.m 檔案, 修改如下:
....
//@add: render something
- (void)render
{
// Specify the RGB and alpha (transparency) values to use when clearing the screen.
//
//glClearColor(0, 104.0/255.0, 55.0/255.0, 1.0); // 除法會降低效能
glClearColor(0.0, 0.4078, 0.2157, 1.0);
// Actually perform the clearing
glClear(GL_COLOR_BUFFER_BIT);
//@add: draw our new vertex data to the screen
//
// 1. 設定要繪製在 UIView 上的範圍, 此處為畫到整個視窗上
glViewport(0, 0, self.frame.size.width, self.frame.size.height);
// 2. 定義頂點的屬性資料(之後便可設定 vertex shader 的 attributes 變數之值:
// Position, SourceColor)
//
// a. 當在繪製時, OpenGL 會從儲存在緩衝區物件裡的陣列取得頂點資料.
// b. 我們需要告訴 OpenGL 儲存在緩衝區物件裡的頂點陣列資料是什麼格式.
// c. 亦即, 我們需要告訴 OpenGL 如何去理解儲存在緩衝區裡的陣列資料.
// d. 當 glVertexAttribPointer 函式被呼叫時, 它會參照到此時任何綁定到
// GL_ARRAY_BUFFER 的緩衝區, 在此處為 setupVBOs 函式中的 vertexBuffer.
//
// void glVertexAttribPointer(GLuint index,
// GLint size,
// GLenum type,
// GLboolean normalized,
// GLsizei stride,
// const GLvoid * pointer);
//
// 參數說明
// index: 即將被設定的 vertex shader 的 attribute 之索引位置,
// 之前已在 compileShaders 函式中呼叫 glGetAttribLocation 取得.
//
// size: 每個頂點屬性的元素數量, 在此為:位置 3 個(x,y,z); 顏色 4 個(r,g,b,a).
//
// type: 每個元素的資料型別, 在此, 位置與顏色皆為 GL_FLOAT.
//
// normalized: 是否要對頂點進行正規化處理, 在此為否: GL_FALSE
//
// stride(跨度): 二個連續頂點屬性之間的位元偏移量.
// 亦即, 包含個別頂點資料的資料結構之大小, 在此皆為: sizeof(Vertex)
//
// pointer: 在儲存該屬性的資料結構中, 此屬性資料的起始偏移量.
//
// typedef struct {
// float Position[3];
// float Color[4];
// } Vertex;
//
// 說明:
// a. Position 資料是位於 struct 的起始處, 因此偏移量為: 0.
// b. Color 資料是位於 Position 資料之後, 因此偏移量為: sizeof(float) * 3.
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE,
sizeof(Vertex), 0);
glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE,
sizeof(Vertex), (GLvoid *) (sizeof(float) * 3));
// 3. 對每個傳入的頂點呼叫 vertex shader, 然後對每個像素呼叫 fragment shader,
// 最後顯示在螢幕上.
//
// void glDrawElements(GLenum mode,
// GLsizei count,
// GLenum type,
// const GLvoid * indices);
//
// 參數說明
// mode: 要繪製的基本圖形種類
//
// count: 要繪製的頂點數量
//
// type: 索引陣列中, 每個個別索引的資料型別(GLubyte)
//
// indices: 指向索引陣列的指標.
// 在此為特例, 由於使用了 Vertex Buffer Objects, 因此它會使用
// 在 setupVBOs 函式中與 GL_ELEMENT_ARRAY_BUFFER 綁定,
// 儲存在 Index Buffer object 裡的 Indices 陣列.
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]),
GL_UNSIGNED_BYTE, 0);
// Present the render/color buffer to the UIView's layer!
[_context presentRenderbuffer:GL_RENDERBUFFER];
}
....
----------------------------------------------------------------------------------
D. 編譯並執行:
說明:
預設情況下, OpenGL 的 "攝影機" 是位於 (0, 0, 0), 並朝著 Z 軸方向望去.
左下角的座標為(-1, -1), 右上角的座標為(1, 1), "攝影機"的可視範圍剛好
涵蓋住我們所建立的正方形. 所以整個螢幕範圍都是繪製的區域.
預設情況下, OpenGL 的 "攝影機" 是位於 (0, 0, 0), 並朝著 Z 軸方向望去.
左下角的座標為(-1, -1), 右上角的座標為(1, 1), "攝影機"的可視範圍剛好
涵蓋住我們所建立的正方形. 所以整個螢幕範圍都是繪製的區域.
沒有留言:
張貼留言
注意:只有此網誌的成員可以留言。