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 2 - 1
GLKBaseEffect 實作
A. 建立一個 GLKBaseEffect
開啟 HelloGLKitViewController.m 檔案, 修改如下:
....
// step 1:
@interface HelloGLKitViewController ()
{
//@add
float _curRed;
BOOL _increasing;
GLuint _vertexBuffer;
GLuint _indexBuffer;
GLKBaseEffect *effect;
float _rotation;
}
//@add
@property (strong, nonatomic) EAGLContext *context;
@property (strong, nonatomic) GLKBaseEffect *effect;
@end
....
// step 2:
- (void)setupGL
{
// Set the current OpenGL context to the current context.
[EAGLContext setCurrentContext:self.context];
//@add for initialize GLKBaseEffect
self.effect = [[GLKBaseEffect alloc] init];
....
}
....
// step 3:
- (void)tearDownGL
{
[EAGLContext setCurrentContext:self.context];
glDeleteBuffers(1, &_vertexBuffer);
glDeleteBuffers(1, &_indexBuffer);
//@add
self.effect = nil;
}
....
----------------------------------------------------------------------------------
B. 設定 GLKBaseEffect 屬性
1. 說明:
a. 第一個需要設定的屬性為: 投影矩陣. 投影矩陣是用來告訴 CPU 如何在 2D
的平面上繪製出 3D 的幾何圖形.
b. GLKit 提供了一些便利的函式來設定投影矩陣. 我們將使用其中一個來設定:
(1). 沿著 Y 軸的視野角度 (fovy: field of view along the y-axis),
即上下二個平面的夾角.
(2). 寬與高的比例 (aspect ratio: w / h)
(3). 近端與遠端平面 (near and far planes)
c. Field of view 就像是相機的鏡頭. 較小的 field of view (例如: 10), 類似攝遠
鏡頭 - 藉由將圖片向你拉近而使圖片放大. 較大的 field of view (例如: 100),
類似廣角鏡頭 - 它讓所有物體看起來較遠. 一般設定 Field of view 的值介於:
65 - 75 之間.
d. Aspect ratio 是你想要繪製的方向比例(亦即, view 的方向比例). 它與 field
of view 結合使用, 來決定沿著 X 軸的視野大小.
e. 近端與遠端平面, 是場景中用來框住可視空間的容量邊界. 所以, 如果某個
物體與眼睛(相機)的距離過近於近端平面或過遠於遠端平面, 它就不會被
繪製出來. 這是一個普遍可能會遇到的問題 - 你在繪製一個物體, 但是它沒有
在螢幕上顯示出來. 記得要去檢查: 這個物體是否位於 near plane 與 far plane
之間.
********************************************************
2. 開啟 HelloGLKitViewController.m 檔案, 修改如下:
// 設定投影矩陣
....
- (void)update
{
....
//@add: set the projection matrix
//
// 1. get the aspect ratio of the GLKView.
float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);
// 2. Create a perspective matrix: (with GLKit math library)
//
// We set the near plane to 4 units away from the eye, and the far plane
// to 10 units away.
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 4.0f, 10.0f);
// 3. Set the projection matrix on the effect's transform property
self.effect.transform.projectionMatrix = projectionMatrix;
}
....
********************************************************
3. 設定 modelView 矩陣
a. 說明:
ModelViewMatrix 是要繪製的幾何物體效果都需要套用的轉換.
在此, 又藉由 GLKit 數學函式庫的協助, 來執行位移, 旋轉與縮放的功能.
b. 開啟 HelloGLKitViewController.m 檔案, 修改如下:
....
- (void)update
{
....
//@add: set the projection matrix
....
//@add: set the modelViewMatrix
//
// 1. Move z-coordinate backwards.
// Create a matrix for us that translates 6 units(Z) backwards.
//
// Because when we set up the vertices for the square, the z-coordinate
// for each vertex was 0.
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -6.0f);
// 2. Increment rotate variable
_rotation += 90 * self.timeSinceLastUpdate;
// 3. Rotating it
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, GLKMathDegreesToRadians(_rotation), 0, 0, 1);
// 4. Set the model view matrix on the effect's transform property.
self.effect.transform.modelviewMatrix = modelViewMatrix;
}
....
----------------------------------------------------------------------------------
C. 在 GLKBaseEffect 上呼叫 prepareToDraw
1. 說明:在將物體繪製到螢幕之前, 任何時候你在 GLKBaseEffect 上更改了屬性設定,
都需要先呼叫此方法.
2. 開啟 HelloGLKitViewController.m 檔案, 修改如下:
....
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClearColor(_curRed, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
//@add
[self.effect prepareToDraw];
}
....
----------------------------------------------------------------------------------
D. 啟用 "預先定義好的" 的屬性
1. 開啟 HelloGLKitViewController.m 檔案, 修改如下:
....
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClearColor(_curRed, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
//@add
[self.effect prepareToDraw];
//@add: Enable pre-defined attributes
//
// 1. bind the vertex and index buffers
//
// Every time before you draw, you have to tell OpenGL which vertex buffer objects
// you should use. So here we bind the vertex and index buffers we created earlier.
//
// Strictly, we didn't have to do this for this app (because they're already still bound
// from before) but usually you have to do this because in most games you use
// many different vertex buffer objects.
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
// 2. Enable the pre-defined vertex attributes (position)
// and feed the correct values to input variables for the vertex shader.
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid *) offsetof(Vertex, Position));
// 3. Enable the pre-defined vertex attributes (color)
// and feed the correct values to input variables for the vertex shader.
glEnableVertexAttribArray(GLKVertexAttribColor);
glVertexAttribPointer(GLKVertexAttribColor, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid *) offsetof(Vertex, Color));
}
....
********************************************************
2. glVertexAttribPointer 參數說明:
void glVertexAttribPointer(GLuint index,
GLint size,
GLenum type,
GLboolean normalized,
GLsizei stride,
const GLvoid *pointer);
a. index:
即將被設定的 vertex shader 的 attribute 之索引位置,
在此, 我們使用 GLKit 提供的 "預先定義好的" 常數值.
(若不使用 GLKit 的話, 需呼叫 glGetAttribLocation 來取得)
b. size:
每個頂點屬性的元素數量, 在此為:位置 3 個(x,y,z); 顏色 4 個(r,g,b,a).
c. type:
每個元素的資料型別, 在此, 位置與顏色皆為 GL_FLOAT.
d. normalized:
是否要對頂點進行正規化處理, 在此為否: GL_FALSE
e. stride:
跨度: 二個連續頂點屬性之間的位元偏移量.
亦即, 包含個別頂點資料的資料結構之大小, 在此皆為: sizeof(Vertex)
f. pointer:
在儲存該屬性的資料結構中, 此屬性資料的起始偏移量.
在此, 可以使用 offsetof 運算子, 來找出在一個結構體中, 特定資料欄位的
起始偏移量.
備註: 不然的話, 就要依照 struct 的內容來計算:
typedef struct {
float Position[3];
float Color[4];
} Vertex;
=> Position 資料是位於 struct 的起始處, 因此偏移量為: 0.
=> Color 資料是位於 Position 資料之後, 因此偏移量為: sizeof(float) * 3.
----------------------------------------------------------------------------------
E. 繪製幾何圖形
1. 開啟 HelloGLKitViewController.m 檔案, 修改如下:
....
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClearColor(_curRed, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
//@add
[self.effect prepareToDraw];
//@add: Enable pre-defined attributes
....
//@add: Draw geometry
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);
}
....
2. glDrawElements 參數說明:
void glDrawElements(GLenum mode,
GLsizei count,
GLenum type,
const GLvoid *indices);
a. mode:
要繪製的基本圖形種類.
b. count:
要繪製的頂點數量.
c. type:
索引陣列中, 每個個別索引的資料型別(GLubyte)
d. indices:
指向索引陣列的指標.
備註:
在此為特例, 由於使用了 Vertex Buffer Objects, 因此它會使用
在 glkView:drawInRect: 函式中與 GL_ELEMENT_ARRAY_BUFFER 綁定,
儲存在 Index Buffer object 裡的 Indices 陣列.
----------------------------------------------------------------------------------
F. 編譯並執行:
可以在螢幕上看到一個漂亮的旋轉方塊.
(背景仍然是: 脈動式的 "緊急警報" 效果: 黑 -> 漸紅 -> 紅)
沒有留言:
張貼留言
注意:只有此網誌的成員可以留言。