iOS-零基礎學習OpenGL-ES入門教程(一)

AceDong發表於2018-07-04

寫在前面

因為做的攝像頭相關工作,工作中常用到OpenGL去做視訊渲染,圖形變換等,雖說滿足了開發需求,但是自己對於OpenGL的學習一直沒有很系統完善,屬於需求驅動學習。所以才有了這個開篇

OpenGL ES的開始學習必然是有一點點枯燥和難理解的哈,沒有C語言程式設計基礎的童鞋,初次接觸C介面程式設計會有一點疑惑,但是沒關係,所謂孰能生巧,多思考,練習即可。

學習書籍這塊:

  1. OpenGL ES應用開發實踐指南:iOS卷
  2. 紅寶書 OpenGL Programming Guide,出到第八版
  3. 藍寶書 OpenGL SuperBible,出到第六版

入門教程以及demo程式碼主要來源於《OpenGL ES應用開發實踐指南:iOS卷》

1.OpenGL ES概述

關於概念介紹我就貼上百度了哈(哈哈,偷懶一下) OpenGL ES百度百科

OK,OpenGL是用於2D/3D圖形程式設計的一套基於C語言的統一介面,在桌面windows,Mac,Linux/Unix上均可相容。

OpenGL ES是在OpenGL嵌入式裝置上面的版本,也就是安卓/iPhone,其他嵌入式等移動裝置的程式設計規範。(除此之外,在web上也有相應的WebGL)

現在在iOS平臺上目前支援的OpenGL版本有

  • OpenGL1.0
  • OpenGL2.0
  • OpenGL3.0

後面的教程均基於OpenGL2.0環境下。(其中1.0版本基本已經不再使用了。)

從上面的簡單介紹我們知道了OpenGL ES是做圖形程式設計的, 下圖摘自蘋果的官方介紹: OpenGL ES Programming Guide

cpu_gpu_2x.png

可以看到我們通過OpenGL ES驅動gpu圖形處理器實現圖形程式設計。

發散小思考: OpenGL ES作為iOS相對底層庫,可以完成2D/3D圖形渲染,那麼我們平常的UIView也可以基於CoreAnimation完成3D動畫,圖形顯示,那麼UIView和OpenGL有什麼內在關係呢,我們的iPhone最終是怎麼完成影象顯示的呢?

Cocoa Touch OpenGL ES軟體架構

從上圖可以看到core animation Layers就是通過OpenGL ES繪製最後混合,然後通過幀快取顯示到螢幕上的。

2.iOS OpenGL ES最簡單的實踐

OK,由於是開篇,下面我們通過一個簡單的例子完成一個三角形的繪製 在這裡我們使用GLkit:這是蘋果做的一層封裝,可以簡化在iOS下OPENGL ES程式碼。

至於GLkit具體做了什麼,後面隨著我們深入學習可以再回頭來看,後面會編寫不使用GLkit的demo,可以通過比對來看到底優化了哪些流程,這裡暫時只需要記住使用GLkit可以簡化程式碼。

  • GLKViewController:UIViewController的子類,接收當檢視需要重繪時的訊息
  • GLKView:UIView的子類,簡化了通過用Core Animation層來自動建立並管理幀快取和渲染快取共享記憶體所需要做的工作。
  1. 建立OpenGL ES上下文 建立一個GLKViewController,在ViewdidLoad生命週期中:
    GLKView *view  = (GLKView *)self.view;
    //建立OpenGL ES2.0上下文
    view.context = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
    //設定當前上下文
    [EAGLContext setCurrentContext:view.context];
複製程式碼
  1. 宣告一個GLKBaseEffect屬性
@property (nonatomic,strong)GLKBaseEffect *baseEffect;
複製程式碼

並且在ViewDidLoad例項化

  self.baseEffect = [[GLKBaseEffect alloc]init];
//使用靜態顏色繪製
  self.baseEffect.useConstantColor = GL_TRUE;
//設定預設繪製顏色,引數分別是 RGBA
  self.baseEffect.constantColor = GLKVector4Make(1.0f, 1.0f, 1.0f, 1.0f);
   //設定背景色為黑色
   glClearColor(0.0f,0.0f,0.0f,1.0f);
複製程式碼

GLKBaseEffect使我們不需要編寫shader Language程式碼就可以簡單完成圖形繪製,關於Shader Language後面再講解學習

  1. 頂點資料 我們需要繪製一個三角形自然需要三個頂點,OpenGL ES採用的笛卡爾座標系
    OPENGL ES座標系
//頂點結構體
typedef struct{
    GLKVector3 positionCoords;
}sceneVertex;

//三角形的三個頂點
static const sceneVertex vertices[] = {
    {{-0.5f,-0.5f,0.0}},
    {{0.5f,-0.5f,0.0}},
    {{-0.5f,0.5f,0.0}},
};
複製程式碼
  1. 生成快取並且為快取提供資料,這是最重要的一步
//宣告快取ID屬性
@property (nonatomic,assign)GLuint *vertextBufferID;
複製程式碼
  //viewdidload中生成並繫結快取資料
  glGenBuffers(1, &vertextBufferID);
  glBindBuffer(GL_ARRAY_BUFFER, vertextBufferID); //繫結指定識別符號的快取為當前快取
  glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
複製程式碼
  • glGenBuffers申請一個識別符號
  • glBindBuffer 將識別符號繫結到GL_ARRAY_BUFFER
  • glBufferData複製頂點資料從CPU到GPU

接下來在GLKViewController的 -(void)glkView:(GLKView *)view drawInRect:(CGRect)rect 代理方法中

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
    [self.baseEffect prepareToDraw];
    
    //Clear Frame Buffer
    glClear(GL_COLOR_BUFFER_BIT);
    
    //開啟快取
    glEnableVertexAttribArray(GLKVertexAttribPosition);
    
    //設定快取資料指標
    glVertexAttribPointer(GLKVertexAttribPosition,
                          3,
                          GL_FLOAT,
                          GL_FALSE, //小數點固定資料是否被改變
                          sizeof(sceneVertex),
                          NULL);  //從開始位置
    //繪圖
    glDrawArrays(GL_TRIANGLES,
                 0,
                 3);

}
複製程式碼
  • glEnableVertexAttribArray 開啟對應的頂點快取屬性
  • glVertexAttribPointer 設定指標從頂點陣列中讀取資料
  • glDrawArrays 繪製圖形
  1. 釋放快取資料 在dealloc方法中釋放掉快取資料
- (void)dealloc{
    GLKView *view = (GLKView *)self.view;
    [EAGLContext setCurrentContext:view.context];
    if ( 0 != vertextBufferID) {
        glDeleteBuffers(1,
                        &vertextBufferID);
        vertextBufferID = 0;
    }
}
複製程式碼

最後的執行結果圖如下

執行結果

擴充小問題:1. 如何將背景色改成紅色 2. 如何將三角形顏色改成黑色,而不是現在的白色

  • (void)glkView:(GLKView *)view drawInRect:(CGRect)rect是GLKViewController系統給我們回撥的繪製訊息,該方法會一直被呼叫,和display方法一致

EAGLContext上下文字質上是個狀態機,只有在當前上下文下,Opengl ES API呼叫才會生效

3.總結: 建立快取資料並完成最終渲染顯示的七個步驟

  1. 生成: glGenBuffers()
  2. 繫結快取資料: glBindBuffer()
  3. 快取資料:glBufferData()
  4. 啟用:glEnableVertexAttribArray()
  5. 設定指標:glVertexAttribPointer()
  6. 繪圖:glDrawArrays()
  7. 刪除:glDeleteBuffers()

好了,就此我們就使用OpenGL ES完成了一個最簡單的繪製demo,初次學習OpenGL ES肯定對其中概念會有很多疑問,這都沒關係,我們先熟悉一下,隨著後續的學習再回來看這些疑問。

2017-0413更新: Demo程式碼地址:LearnOpenGLESDemo

參考書籍:1. OpenGL ES應用開發實踐指南:iOS卷

相關文章