版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2017.07.22 |
前言
OpenGL 圖形庫項目中一直也沒用過,最近也想學著使用這個圖形庫,感覺還是很有意思,也就自然想著好好的總結一下。首先要給大家介紹個學習網站。
1. 歡迎來到OpenGL的世界
2.系列教程
3.教程代碼
4.落影簡書
OpenGL ES基礎
OpenGL ES
是一套多功能開放標準的用于嵌入系統的C-based
的圖形庫,用于2D
和3D
數據的可視化。OpenGL
被設計用來轉換一組圖形調用功能到底層圖形硬件(GPU)
,由GPU
執行圖形命令,用來實現復雜的圖形操作和運算,從而能夠高性能、高幀率利用GPU
提供的2D
和3D
繪制能力。
OpenGL ES
規范本身不定義繪制表面和繪制窗口,因此ios為了使用它必須提供和創建一個OpenGL ES
的呈現環境,創建和配置存儲繪制命令結果的framebuffer
及創建和配置一個或多個呈現目標。在 iOS中使用EAGL
提供的EAGLContext
類 來實現和提供一個呈現環境,用來保持OpenGLES
使用到的硬件狀態。 EAGL
是一個Objective-C API
,提供使OpenGL ES
與Core Animation
和UIKIT
集成的接口。
在調用任何OpenGL ES
功能之前必須首先初始化一個EAGLContext
對象。每一個iOS應用的每一個線程都有一個當前context
,在調用OpenGLES
函數時,使用或改變此context
中的狀態。EAGLContext
的類方法setCurrentContext:
用來設置當前線程的當前context
。EAGLContext
的類方法currentContext
返回當前線程的當前context
。在切換相同線程的兩個上下文之前,必須調用glFlush
函數來確保先前已提交的命令被提交到圖形硬件中。
可以采用不同的方式使用OpenGL ES
以便呈現OpenGL ES
內容到不同的目標:GLKit
和CAEAGLLayer
。為了創建全屏幕的視圖或使OpenGL ES
內容與UIKit
視圖集成,可以使用GLKit
。在使用GLKit
時,GLKit
提供的類GLKView
類本身實現呈現目標及創建和維護一個framebuffer
。
為了使OpenGL ES
內容作為一個Core Animation
層的部分內容時,可以使用CAEAGLLayer
作為呈現目標,并需要另外創建framebuffer
以及自己實現和控制整個繪制流程。
GLKit
是一組objective-c
類,為使用OpenGL ES
提供一個面向對象接口,用來簡化OpenGL ES
應用的開發。GLKit
支持四個3D
應用開發的關鍵領域:
-
GLKView
和GLKViewController
類提供一個標準的OpenGL ES
視圖和相關聯的呈現循環。GLKView
可以作為OpenGL ES
內容的呈現目標,GLKViewController
提供內容呈現的控制和動畫。視圖管理和維護一個framebuffer
,應用只需在framebuffer
進行繪畫即可。 -
GLKTextureLoader
為應用提供從iOS支持的各種圖像格式的源自動加載紋理圖像到OpenGL ES
圖像環境的方式,并能夠進行適當的轉換,并支持同步和異步加載方式。 - 數學運算庫,提供向量、矩陣、四元數的實現和矩陣堆棧操作等
OpenGL ES 1.1
功能。 -
Effect
效果類提供標準的公共著色效果的實現。能夠配置效果和相關的頂點數據,然后創建和加載適當的著色器。GLKit
包括三個可配置著色效果類:GLKBaseEffect
實現OpenGL ES 1.1
規范中的關鍵的燈光和材料模式,GLKSkyboxEffect
提供一個skybox
效果的實現,GLKReflectionMapEffect
在GLKBaseEffect
基礎上包括反射映射支持。
GLKView和OpenGL ES繪制過程
使用GLKView和OpenGLES進行繪制過程:
創建一個
GLKView
對象。
GLKView
對象可以編程或使用Interface Builder
來創建和配置。在采用編程方式時,首先創建一個context
然后調用initWithFrame:context:
方法。使用Interface Builder
方式時,在從storyboard
加載一個GLKView
后,創建一個context
和設置它作為視圖的context
屬性。在iOS
中GLKit
的使用需要創建OpenGL ES 2.0
以上的圖形環境context
。GLKit
視圖自動創建和配置它所有的OpenGLES framebuffer
對象和renderbuffers
,可以通過修改視圖的drawable
屬性來控制這些對象的屬性。-
繪制
OpenGL
內容(發布繪制命令)
使用GLKit
視圖繪制OpenGL
內容需要三個子步驟:- 準備
OpenGL ES
基礎; - 發布繪制命令;
- 呈現顯示內容到
Core Animation
。
- 準備
GLKit
類本身已經實現了第一個和第三個步驟,用戶只需實現第二個步驟,在視圖的方法drawRect
或視圖的代理對象的glkView:drawInRect:
中調用適當的OpenGL ES
繪制命令進行內容繪制。GLKViewController
類維護一個animation
呈現循環(包含兩個方法update
和display
),用來實現連續的動畫復雜的場景。animation
呈現循環的交替速率由GLKViewController
的屬性framesPerSecond
指示,并使用preferredFramesPerSecond
屬性來修改它。
OpenGL ES版本
iOS
系統默認支持OpenGl ES1.0
、ES2.0
以及ES3.0
3個版本,三者之間并不是簡單的版本升級,設計理念甚至完全不同,在開發OpenGL
項目前,需要根據業務需求選擇合適的版本。在學習OpenGL
代碼的時候也需要知道它對應著哪個版本,在ES1
中執行ES2
代碼是看不到任何效果的,你可以在初始化EAGLContext
時指定ES
版本號。
指定版本方法如下所示。
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
OpenGL ES坐標系
OpenGL ES
坐標系和UI
的坐標系是不同的,具體如下所示。
UI
是以左上角為原點的,而OpenGL ES
坐標系是以屏幕中心為原點的。除了方向,還有一點需要注意,默認情況各個方向坐標值范圍為(-1,1)
,而不是UIKit
中的(0,320)
。當繪制點(320,0)
時,它并不會出現在屏幕右上角。在ES1
中,可以通過以下代碼將坐標系轉化為熟悉的(320,480)
。下面我們看代碼。
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glViewport(0, 0, rect.size.width * 2, rect.size.height * 2);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(0, 320, 0, 480, -1024, 1024);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
幾個重要的類
下面介紹幾個重要的類。
1. GLKViewController & GLKView
為了方便大家更快的開發,系統為OpenGL
提供了簡單的封裝,繼承GLKViewController
定義自己的ViewController
,GLKViewController
的view
為GLKView
類,GLKView
的delegate
定義了繪制回調函數。
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
GLKViewController
定義數據刷新函數,當子類實現-(void)update
方法,glkViewControllerUpdate
方法將不再被調用。
- (void)glkViewControllerUpdate:(GLKViewController *)controller
需要補充一點,默認情況下,GLKViewController
渲染RunLoop
并非NSRunLoopCommonModes
,而是NSDefaultRunLoopMode
,因此在UIKit
中使用GLKViewController
,當滑動界面時,OpenGL
是不會渲染的。
2. EAGLContext
在介紹選擇版本時已經提到EAGLContext
,與UIKit
中CGContextRef
相似,EAGLContext
相當于OpenGL
繪制句柄或者上下文,在繪制試圖之前,需要指定使用創建的上下文繪制。
[EAGLContext setCurrentContext:view.context];
當一個APP可能存在多個EAGLContext
時,需要處理并存沖突等問題,比如大家所熟知的GPUImage,都會使用到EAGLContext
。因此,在使用中要記得及時釋放。有興趣的朋友可以看看這篇文章。
這里還需要記住的是:當App退到后臺時, 切記暫停OpenGL
繪制,否則可能導致crash
。
后記
這篇主要是基本的介紹和幾個基礎概念,后面還會繼續給大家擴展,畢竟基礎的部分是固定的。未完,待續~~~