2012年3月31日 星期六

OpenGL ES 入門: 二. 簡單繪圖之二

since: 2012/03/31
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. 編譯並執行
          三角形將沿着原點緩緩轉動


沒有留言:

張貼留言

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