寫在前面
因為做的攝像頭相關工作,工作中常用到OpenGL去做視訊渲染,圖形變換等,雖說滿足了開發需求,但是自己對於OpenGL的學習一直沒有很系統完善,屬於需求驅動學習。所以才有了這個開篇
OpenGL ES的開始學習必然是有一點點枯燥和難理解的哈,沒有C語言程式設計基礎的童鞋,初次接觸C介面程式設計會有一點疑惑,但是沒關係,所謂孰能生巧,多思考,練習即可。
學習書籍這塊:
- OpenGL ES應用開發實踐指南:iOS卷
- 紅寶書 OpenGL Programming Guide,出到第八版
- 藍寶書 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
可以看到我們通過OpenGL ES驅動gpu圖形處理器實現圖形程式設計。
發散小思考: OpenGL ES作為iOS相對底層庫,可以完成2D/3D圖形渲染,那麼我們平常的UIView也可以基於CoreAnimation完成3D動畫,圖形顯示,那麼UIView和OpenGL有什麼內在關係呢,我們的iPhone最終是怎麼完成影象顯示的呢?
從上圖可以看到core animation Layers就是通過OpenGL ES繪製最後混合,然後通過幀快取顯示到螢幕上的。
2.iOS OpenGL ES最簡單的實踐
OK,由於是開篇,下面我們通過一個簡單的例子完成一個三角形的繪製 在這裡我們使用GLkit:這是蘋果做的一層封裝,可以簡化在iOS下OPENGL ES程式碼。
至於GLkit具體做了什麼,後面隨著我們深入學習可以再回頭來看,後面會編寫不使用GLkit的demo,可以通過比對來看到底優化了哪些流程,這裡暫時只需要記住使用GLkit可以簡化程式碼。
- GLKViewController:UIViewController的子類,接收當檢視需要重繪時的訊息
- GLKView:UIView的子類,簡化了通過用Core Animation層來自動建立並管理幀快取和渲染快取共享記憶體所需要做的工作。
- 建立OpenGL ES上下文 建立一個GLKViewController,在ViewdidLoad生命週期中:
GLKView *view = (GLKView *)self.view;
//建立OpenGL ES2.0上下文
view.context = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
//設定當前上下文
[EAGLContext setCurrentContext:view.context];
複製程式碼
- 宣告一個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後面再講解學習
- 頂點資料 我們需要繪製一個三角形自然需要三個頂點,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}},
};
複製程式碼
- 生成快取並且為快取提供資料,這是最重要的一步
//宣告快取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 繪製圖形
- 釋放快取資料 在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.總結: 建立快取資料並完成最終渲染顯示的七個步驟
- 生成: glGenBuffers()
- 繫結快取資料: glBindBuffer()
- 快取資料:glBufferData()
- 啟用:glEnableVertexAttribArray()
- 設定指標:glVertexAttribPointer()
- 繪圖:glDrawArrays()
- 刪除:glDeleteBuffers()
好了,就此我們就使用OpenGL ES完成了一個最簡單的繪製demo,初次學習OpenGL ES肯定對其中概念會有很多疑問,這都沒關係,我們先熟悉一下,隨著後續的學習再回來看這些疑問。
2017-0413更新: Demo程式碼地址:LearnOpenGLESDemo
參考書籍:1. OpenGL ES應用開發實踐指南:iOS卷