update: 2012/03/31
reference:
1. 原文:
iPhone Development: OpenGL ES From the Ground Up, Part 2: A Look at Simple Drawing
2. 翻譯:
從零開始學習OpenGL ES之二 – 簡單繪圖概述
3. DirectX、OpenGL及各種圖型函式庫
簡單繪圖之二: 畫三角形與渲染頻率
A. 畫三角形
1. 開啓 ViewController.m 檔案, 修改如下....
//@add for <GLViewDelegate> method
- (void)drawView:(GLView *)view
{
NSLog(@"step 07. ViewController => drawView:");
// Draw code here
/*
glClearColor(0.5f, 0.5f, 0.5f, 1); // 將顏色定義為灰色
glClear(GL_COLOR_BUFFER_BIT); // 執行清除操作
*/
/*************************************************/
/* 畫三角形 */
// 建立三個頂點
//
// 三個頂點的 z 值是一樣的,其值(-3.0)是處於原點 "之後" 的
Vertex3D vertex1 = Vertex3DMake(0.0, 1.0, -3.0);
Vertex3D vertex2 = Vertex3DMake(1.0, 0.0, -3.0);
Vertex3D vertex3 = Vertex3DMake(-1.0, 0.0, -3.0);
// 建立三角形
Triangle3D triangle = Triangle3DMake(vertex1, vertex2, vertex3);
// 將 OpenGL 中的矩陣設為單位矩陣.
// 所謂的單位矩陣是矩陣乘法下的單位元素,
// 任何矩陣乘上單位矩陣都還是等於自己
//
// 所以 glLoadIdentity() 的作用是不希望之前的矩陣資料,
// 殘留到現在的運算.
glLoadIdentity();
// 告訴 OpenGL 所有的繪製工作是在一個灰色背景上進行.
//
// 設定: R, G, B, alpha(1.0, 代表完全不透明)
// 白色: (1.0, 1.0, 1.0, 1.0)
// 黑色: (0.0, 0.0, 0.0, 1.0)
glClearColor(0.7, 0.7, 0.7, 1.0);
// 通知 OpenGL 清除以前的一切圖形並將其設為 clear 顏色.
//
// color buffer - 顏色緩存, 保存當前 frame 各像素的顏色, 基本上就是你在屏幕上
// 看到的.
//
// depth buffer - 深度緩存(z-buffer), 保存每個潛在像素離觀察者距離的信息,
// 使用此信息可以確定一個像素是否需要被繪製出來
//
// 記住: 在繪製一個 frame 之前, 必須清除這兩個緩存以保證不會和以前的內容混雜.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 啟動 OpenGL 的 vertex arrays(頂點陣列)的特性.
// 作為基本準則, 我們可以先啟動最後再關閉我們使用的功能
//
glEnableClientState(GL_VERTEX_ARRAY);
// 設置繪圖時所需的顏色
// 此行代碼將繪圖顏色設為鮮艷的紅色
//
// 現在, 直到下次調用 glColor4f() 前所有的圖形都是以紅色繪製
// 有一些例外的情況, 例如繪製紋理形狀時, 但基本上, 這樣設定顏色可以使顏色保持.
glColor4f(1.0, 0.0, 0.0, 1.0);
// 由於我們使用頂點陣列, 我們必須通知 OpenGL 頂點的陣列在什麼地方.
//
// 頂點陣列只是一個 GLfloat 的 C 陣列, 每三個值代表一個頂點.
// 我們創建了 Triangle3D 物體, 但在內存中, 它完全等同於 9 個連續的 GLfloat,
// 所以我們可以傳遞此三角形物體的位址.
//
// glVertexPointer()
// 第一個參數, 指示了多少個 GLfloat 代表一個頂點
// 第二個參數, 告訴 OpenGL 頂點是由 GLfloat 構成
glVertexPointer(3, GL_FLOAT, 0, &triangle);
// 通知 OpenGL 通過剛才提交的頂點陣列來繪製三角形
//
// 第一個參數, 告訴 OpenGL 繪製什麼.
// 儘管 OpenGL ES 不支持繪製三角形之外的四邊形或其他多邊形, 但它仍然支持
// 一些其他繪圖模式, 如繪製點, 線, 線迴路, 三角形條和三角形扇.
glDrawArrays(GL_TRIANGLES, 0, 9);
// 最後, 我們要禁止先前啟動了的特性以保證不會被其他地方的代碼弄混
glDisableClientState(GL_VERTEX_ARRAY);
}
....
2. 編譯並執行
B. 渲染頻率
1. 開啓 GLView.h 檔案, 修改如下:....
@interface GLView : UIView
{
....
//@add for Rendering Frequency
NSTimer *animationTimer; // 計時器
NSTimeInterval animationInterval; // 間隔多久執行(秒)
NSNumber *currentRunCount; // 目前執行次數
int totalRunTime; // 總執行時間(秒)
}
....
//@add for Rendering Frequency
@property (nonatomic, assign) NSTimer *animationTimer;
@property (nonatomic, assign) NSTimeInterval animationInterval;
@property (nonatomic, strong) NSNumber *currentRunCount;
@property (assign) int totalRunTime;
....
//@add for Rendering Frequency
- (void)startAnimation;
- (void)stopAnimation;
....
2. 開啓 GLView.m 檔案, 修改如下:
....
//@add for Rendering Frequency
@synthesize animationTimer = _animationTimer;
@synthesize animationInterval = _animationInterval;
@synthesize currentRunCount = _currentRunCount;
@synthesize totalRunTime = _totalRunTime;
....
//@add for Rendering Frequency
-(NSNumber *)currentRunCount
{
if (!_currentRunCount) {
_currentRunCount = [[NSNumber alloc] initWithInt:0];
}
return _currentRunCount;
}
//@add for Rendering Frequency
- (void)setAnimationTimer:(NSTimer *)newTimer
{
[_animationTimer invalidate];
_animationTimer = newTimer;
}
//@add for Rendering Frequency
- (void)setAnimationInterval:(NSTimeInterval)interval
{
_animationInterval = interval;
if (self.animationTimer)
{
[self stopAnimation];
[self startAnimation];
}
}
//@add for Rendering Frequency
- (void)startAnimation
{
[self.animationTimer invalidate];
self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:self.animationInterval target:self selector:@selector(drawView) userInfo:nil repeats:YES];
}
//@add for Rendering Frequency
- (void)stopAnimation
{
[self.animationTimer invalidate];
self.animationTimer = nil;
}
....
//@add: overide
- (void)layoutSubviews
{
NSLog(@"step 02. GLView => layoutSubviews");
[EAGLContext setCurrentContext:self.glContext];
//@add for Rendering Frequency
[self setAnimationInterval: 1.0 / kRenderingFrequency];
self.totalRunTime = 10; // 秒
[self destroyFrameBuffer];
[self createFrameBuffer];
//[self drawView];
//@update for Rendering Frequency
[self startAnimation];
}
//@add
- (void)drawView
{
NSLog(@"step 06. GLView => drawView");
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFrameBuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderBuffer);
// GO: step 07. ViewController => drawView:
[self.delegate drawView:self];
[self.glContext presentRenderbuffer:GL_RENDERBUFFER_OES];
//@add for Rendering Frequency
int intCount = [self.currentRunCount intValue] + 1;
self.currentRunCount = [NSNumber numberWithInt:intCount];
if (intCount >= self.totalRunTime * kRenderingFrequency) {
[self stopAnimation];
}
}
//@add
- (void)dealloc
{
//@add for Rendering Frequency
[self stopAnimation];
if ([EAGLContext currentContext] == self.glContext) {
[EAGLContext setCurrentContext:nil];
}
}
....
3. 開啓 ViewController.m 檔案, 修改如下:
....
//@add for <GLViewDelegate> method
- (void)drawView:(GLView *)view
{
NSLog(@"step 07. ViewController => drawView:");
// Draw code here
/*************************************************/
/* 畫三角形 */
//@add for Rendering Frequency
static GLfloat rotation = 0.0;
// 建立三個頂點
//
// 三個頂點的 z 值是一樣的,其值(-3.0)是處於原點 "之後" 的
Vertex3D vertex1 = Vertex3DMake(0.0, 1.0, -3.0);
Vertex3D vertex2 = Vertex3DMake(1.0, 0.0, -3.0);
Vertex3D vertex3 = Vertex3DMake(-1.0, 0.0, -3.0);
// 建立三角形
Triangle3D triangle = Triangle3DMake(vertex1, vertex2, vertex3);
// 將 OpenGL 中的矩陣設為單位矩陣.
// 所謂的單位矩陣是矩陣乘法下的單位元素,
// 任何矩陣乘上單位矩陣都還是等於自己
//
// 所以 glLoadIdentity() 的作用是不希望之前的矩陣資料,
// 殘留到現在的運算.
glLoadIdentity();
//@add for Rendering Frequency
glRotatef(rotation, 0.0, 0.0, 1.0);
// 告訴 OpenGL 所有的繪製工作是在一個灰色背景上進行.
//
// 設定: R, G, B, alpha(1.0, 代表完全不透明)
// 白色: (1.0, 1.0, 1.0, 1.0)
// 黑色: (0.0, 0.0, 0.0, 1.0)
glClearColor(0.7, 0.7, 0.7, 1.0);
// 通知 OpenGL 清除以前的一切圖形並將其設為 clear 顏色.
//
// color buffer - 顏色緩存, 保存當前 frame 各像素的顏色, 基本上就是你在屏幕上
// 看到的.
//
// depth buffer - 深度緩存(z-buffer), 保存每個潛在像素離觀察者距離的信息,
// 使用此信息可以確定一個像素是否需要被繪製出來
//
// 記住: 在繪製一個 frame 之前, 必須清除這兩個緩存以保證不會和以前的內容混雜.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 啟動 OpenGL 的 vertex arrays(頂點陣列)的特性.
// 作為基本準則, 我們可以先啟動最後再關閉我們使用的功能
//
glEnableClientState(GL_VERTEX_ARRAY);
// 設置繪圖時所需的顏色
// 此行代碼將繪圖顏色設為鮮艷的紅色
//
// 現在, 直到下次調用 glColor4f() 前所有的圖形都是以紅色繪製
// 有一些例外的情況, 例如繪製紋理形狀時, 但基本上, 這樣設定顏色可以使顏色保持.
glColor4f(1.0, 0.0, 0.0, 1.0);
// 由於我們使用頂點陣列, 我們必須通知 OpenGL 頂點的陣列在什麼地方.
//
// 頂點陣列只是一個 GLfloat 的 C 陣列, 每三個值代表一個頂點.
// 我們創建了 Triangle3D 物體, 但在內存中, 它完全等同於 9 個連續的 GLfloat,
// 所以我們可以傳遞此三角形物體的位址.
//
// glVertexPointer()
// 第一個參數, 指示了多少個 GLfloat 代表一個頂點
// 第二個參數, 告訴 OpenGL 頂點是由 GLfloat 構成
glVertexPointer(3, GL_FLOAT, 0, &triangle);
// 通知 OpenGL 通過剛才提交的頂點陣列來繪製三角形
//
// 第一個參數, 告訴 OpenGL 繪製什麼.
// 儘管 OpenGL ES 不支持繪製三角形之外的四邊形或其他多邊形, 但它仍然支持
// 一些其他繪圖模式, 如繪製點, 線, 線迴路, 三角形條和三角形扇.
glDrawArrays(GL_TRIANGLES, 0, 9);
// 最後, 我們要禁止先前啟動了的特性以保證不會被其他地方的代碼弄混
glDisableClientState(GL_VERTEX_ARRAY);
//@add for Rendering Frequency
rotation += 0.5;
}
....
4. 編譯並執行
三角形將沿着原點緩緩轉動