OpenGL ES (OpenGL for Embedded Systems) 是以⼿手持和嵌入式爲⽬標的⾼級3D圖形應用程序編程接⼝(API). OpenGL ES 是目前智能手機中佔據統治地位的圖形API.⽀持的平臺: iOS, Andriod , BlackBerry ,bada ,Linux ,Windows.編程
OpenGL ES 開放式圖形庫(OpenGL的)用於可視化的⼆維和三維數據。它是一個多功能開放標準圖形庫,⽀持2D和3D數字內容建立,機械和建築設計,虛擬原型設計,飛⾏模擬,視頻遊戲等應用程序。您可使⽤OpenGL配置3D圖形管道並向其提交數據。頂點被變換和點亮,組合成圖元,並光柵化以建立2D圖像。OpenGL旨在將函數調用轉換爲能夠發送到底層圖形硬件的圖形命令。因爲此底層硬件專用於處理圖形命令,所以OpenGL繪圖一般⾮常快。 OpenGL for Embedded Systems(OpenGL ES)是OpenGL的簡化版本,它消除了了冗餘功能,提供了一個既易於學習又更易於在移動圖形硬件中實現的庫。設計模式
GLKit 框架的設計目標是爲了簡化基於OpenGL / OpenGL ES 的應用開發。它的出現加快OpenGL ES或OpenGL應⽤程序開發。 使用數學庫,背景紋理加載,預先建立的着色器效果,以及標準視圖和視圖控制器來實現渲染循環。 GLKit框架提供了功能和類,能夠減小建立新的基於着色器的應用程序所需的工做量,或者支持依賴早期版本的OpenGL ES或OpenGL提供的固定函數頂點或⽚段處理的現有應用程序。 GLKit的功能: 1.加載紋理 2.提供高性能的數學運算 3.提供常⻅的着⾊器 4.提供視圖以及視圖控制器.數組
GLKit是Cocoa Touch以及多個其餘的框架(包含UIKit)的一部分。GLKView和GLKViewController類是GLKit框架的一部分。 GLKView是Cocoa Touch UIView類的內建子類, 提供繪製場所(View); GLKViewController是UIViewController的內建子類(擴展於標準的UIKit 設計模式. ⽤於繪製視圖內容的管理與呈現.)緩存
新建Xcode工程,在ViewController.h中導入頭文件bash
#import <GLKit/GLKit.h>
#import <OpenGLES/ES3/gl.h>
#import <OpenGLES/ES3/glext.h>
複製代碼
並將ViewController繼承更改成GLKViewController,將ViewController的view的繼承更改成GLKView。服務器
{
EAGLContext *context; //上下文
GLKBaseEffect *cEffect; //完成着色器的工做
}
複製代碼
1.OpenGL ES 相關初始化框架
-(void)setUpConfig
{
//1.初始化上下文&設置當前上下文
context = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES3];
//判斷context是否建立成功
if (!context) {
NSLog(@"Create ES context Failed");
}
//設置當前上下文
[EAGLContext setCurrentContext:context];
//2.獲取GLKView & 設置context
GLKView *view =(GLKView *) self.view;
view.context = context;
//3.配置視圖建立的渲染緩存區.
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
view.drawableDepthFormat = GLKViewDrawableDepthFormat16;
//4.設置背景顏色
glClearColor(1, 0, 0, 1.0);
}
複製代碼
註解1: EAGLContext 是蘋果iOS平臺下實現OpenGLES 渲染層. kEAGLRenderingAPIOpenGLES1 = 1, 固定管線 kEAGLRenderingAPIOpenGLES2 = 2, kEAGLRenderingAPIOpenGLES3 = 3,異步
註解2: (1). drawableColorFormat: 顏色緩存區格式. 簡介: OpenGL ES 有一個緩存區,它用以存儲將在屏幕中顯示的顏色。你可使用其屬性來設置緩衝區中的每一個像素的顏色格式。 GLKViewDrawableColorFormatRGBA8888 = 0, 默認緩存區的每一個像素的最小組成部分(RGBA)使用8個bit,(因此每一個像素4個字節,4*8個bit)。 GLKViewDrawableColorFormatRGB565, 若是你的APP容許更小範圍的顏色,便可設置這個。會讓你的APP消耗更小的資源(內存和處理時間)ide
(2). drawableDepthFormat: 深度緩存區格式 GLKViewDrawableDepthFormatNone = 0,意味着徹底沒有深度緩衝區 GLKViewDrawableDepthFormat16, GLKViewDrawableDepthFormat24, 若是你要使用這個屬性(通常用於3D遊戲),你應該選擇GLKViewDrawableDepthFormat16或GLKViewDrawableDepthFormat24。這裏的差異是使用GLKViewDrawableDepthFormat16將消耗更少的資源函數
2.加載頂點/紋理座標數據
//1.設置頂點數組(頂點座標,紋理座標)
/*
紋理座標系取值範圍[0,1];原點是左下角(0,0);
故而(0,0)是紋理圖像的左下角, 點(1,1)是右上角.
*/
GLfloat vertexData[] = {
0.5, -0.5, 0.0f, 1.0f, 0.0f, //右下
0.5, 0.5, -0.0f, 1.0f, 1.0f, //右上
-0.5, 0.5, 0.0f, 0.0f, 1.0f, //左上
0.5, -0.5, 0.0f, 1.0f, 0.0f, //右下
-0.5, 0.5, 0.0f, 0.0f, 1.0f, //左上
-0.5, -0.5, 0.0f, 0.0f, 0.0f, //左下
};
//2.開闢頂點緩存區
//(1).建立頂點緩存區標識符ID
GLuint bufferID;
glGenBuffers(1, &bufferID);
//(2).綁定頂點緩存區.(明確做用)
glBindBuffer(GL_ARRAY_BUFFER, bufferID);
//(3).將頂點數組的數據copy到頂點緩存區中(GPU顯存中)
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
//3.打開讀取通道.
//頂點座標數據
glEnableVertexAttribArray(GLKVertexAttribPosition);
/*
typedef NS_ENUM(GLint, GLKVertexAttrib)
{
GLKVertexAttribPosition,頂點
GLKVertexAttribNormal,法線
GLKVertexAttribColor,顏色值
GLKVertexAttribTexCoord0,紋理0
GLKVertexAttribTexCoord1 紋理1
} NS_ENUM_AVAILABLE(10_8, 5_0);
*/
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 0);
//紋理座標數據
//打開對應attribute開關
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 3);
複製代碼
註解1: 頂點數組: 開發者能夠選擇設定函數指針,在調用繪製方法的時候,直接由內存傳入頂點數據,也就是說這部分數據以前是存儲在內存當中的,被稱爲頂點數組。
頂點緩存區: 性能更高的作法是,提早分配一塊顯存,將頂點數據預先傳入到顯存當中。這部分的顯存,就被稱爲頂點緩存區。 註解2: (1)在iOS中, 默認狀況下,出於性能考慮,全部頂點着色器的屬性(Attribute)變量都是關閉的. 意味着,頂點數據在着色器端(服務端)是不可用的. 即便你已經使用glBufferData方法,將頂點數據從內存拷貝到頂點緩存區中(GPU顯存中). 因此, 必須由glEnableVertexAttribArray 方法打開通道.指定訪問屬性.才能讓頂點着色器可以訪問到從CPU複製到GPU的數據. 注意: 數據在GPU端是否可見,即,着色器可否讀取到數據,由是否啓用了對應的屬性決定,這就是glEnableVertexAttribArray的功能,容許頂點着色器讀取GPU(服務器端)數據。
(2)方法簡介 glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
功能: 上傳頂點數據到顯存的方法(設置合適的方式從buffer裏面讀取數據) 參數列表: index:指定要修改的頂點屬性的索引值,例如 size:每次讀取數量。(如position是由3個(x,y,z)組成,而顏色是4個(r,g,b,a),紋理則是2個.) type:指定數組中每一個組件的數據類型。可用的符號常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED, 和 GL_FLOAT,初始值爲GL_FLOAT。 normalized:指定當被訪問時,固定點數據值是否應該被歸一化(GL_TRUE)或者直接轉換爲固定點值(GL_FALSE) stride:指定連續頂點屬性之間的偏移量。若是爲0,那麼頂點屬性會被理解爲:它們是緊密排列在一塊兒的。初始值爲0 ptr:指定一個指針,指向數組中第一個頂點屬性的第一個組件,初始值爲0。
3.加載紋理數據(使用GLBaseEffect)
//1.獲取紋理圖片路徑
NSString * filepath = [[NSBundle mainBundle] pathForResource:@"shiyuan1" ofType:@"jpg"];
//2.設置紋理參數
//紋理座標原點是左下角,可是圖片顯示原點應該是左上角.
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:@(1),GLKTextureLoaderOriginBottomLeft, nil];
GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];
//3.使用蘋果GLKit 提供GLKBaseEffect 完成着色器工做(頂點/片元)
cEffect = [[GLKBaseEffect alloc]init];
cEffect.texture2d0.enabled = GL_TRUE;
cEffect.texture2d0.name = textureInfo.name;
複製代碼
4.繪製視圖的內容
#pragma mark -- GLKViewDelegate
//繪製視圖的內容
/*
GLKView對象使其OpenGL ES上下文成爲當前上下文,並將其framebuffer綁定爲OpenGL ES呈現命令的目標。而後,委託方法應該繪製視圖的內容。
*/
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
//1.清除顏色緩存區
glClear(GL_COLOR_BUFFER_BIT);
//2.準備繪製
[cEffect prepareToDraw];
//3.開始繪製
glDrawArrays(GL_TRIANGLES, 0, 6);
}
複製代碼
繪製結果:
1.GLKView
GLKView 使⽤用OpenGL ES 繪製內容的視圖默認實現: 1.初始化新視圖
- (instancetype)initWithFrame:(CGRect)frame context:(EAGLContext *)context;
複製代碼
2.視圖代理
@property (nullable, nonatomic, assign) IBOutlet id <GLKViewDelegate> delegate;
複製代碼
3.繪製視圖內容時使用的OpenGL ES 上下文
@property (nonatomic, retain) EAGLContext *context;
複製代碼
4.配置幀緩存區對象
drawableColorFormat 顏⾊渲染緩存區格式
/*
GLKViewDrawableColorFormatRGBA8888 = 0,
GLKViewDrawableColorFormatRGB565,
GLKViewDrawableColorFormatSRGBA8888,
*/
drawableDepthFormat 深度渲染緩存區格式
/*
GLKViewDrawableDepthFormatNone = 0,
GLKViewDrawableDepthFormat16,
GLKViewDrawableDepthFormat24,
*/
drawableStencilFormat 模板渲染緩存區的格式
/*
GLKViewDrawableStencilFormatNone = 0,
GLKViewDrawableStencilFormat8,
*/
drawableMultisample 多重採樣緩存區的格式
/*
GLKViewDrawableMultisampleNone = 0,
GLKViewDrawableMultisample4X,
*/
複製代碼
5.幀緩存區屬性
drawableHeight 底層緩存區對象的⾼度(以像素爲單位)
drawableWidth 底層緩存區對象的寬度(以像素爲單位)
複製代碼
6.將底層FrameBuffer 對象綁定到OpenGL ES
- (void)bindDrawable;
複製代碼
7.刪除與視圖關聯的可繪製對象/刪除視圖FrameBuffer對象
- (void)deleteDrawable;
複製代碼
8.繪製視圖內容並將其做爲新圖像對象返回
@property (readonly, strong) UIImage *snapshot;
複製代碼
9.布爾值(BOOL),指定視圖是否響應使得視圖內容無效的消息
@property (nonatomic) BOOL enableSetNeedsDisplay;
複製代碼
10.當即重繪視圖內容
- (void)display;
複製代碼
11.繪製視圖內容(必須實現代理)
//GLKViewDelegate ⽤用於GLKView 對象回調⽅方法
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect;
複製代碼
2. GLKViewController
GLKViewController 管理OpenGL ES 渲染循環的視圖控制器 1.視圖控制器的代理
@property (nullable, nonatomic, assign) IBOutlet id <GLKViewControllerDelegate> delegate;
複製代碼
2.配置視圖的幀速率
//視圖控制器調用視圖以及更新視圖內容的速率
@property (nonatomic) NSInteger preferredFramesPerSecond;
//視圖控制器調用視圖以及更新其內容的實際速率
@property (nonatomic, readonly) NSInteger framesPerSecond;
複製代碼
3.控制幀更新
//Bool值,渲染循環是否已暫停
@property (nonatomic, getter=isPaused) BOOL paused;
//Bool值,當前程序從新激活活動狀態時視圖控制器是否自動暫停循環渲染
@property (nonatomic) BOOL pauseOnWillResignActive;
//Bool值,當前程序變爲活動狀態時視圖控制器是否自動恢復呈現渲染
@property (nonatomic) BOOL resumeOnDidBecomeActive;
複製代碼
4.獲取有關視圖view的更新信息
//視圖控制器自建立以來發送的幀更新數
@property (nonatomic, readonly) NSInteger framesDisplayed;
//⾃視圖控制器第⼀次恢復發送更新事件以來通過的時間量
@property (nonatomic, readonly) NSTimeInterval timeSinceFirstResume;
//自上次視圖控制器恢復發送更新事件以來更新的時間量
@property (nonatomic, readonly) NSTimeInterval timeSinceLastResume;
//⾃上次視圖控制器調用委託⽅法以及通過的時間量
@property (nonatomic, readonly) NSTimeInterval timeSinceLastUpdate;
//⾃上次視圖控制器調用視圖display 方法以來通過的時間量
@property (nonatomic, readonly) NSTimeInterval timeSinceLastDraw;
複製代碼
5.渲染循環回調方法--更新視圖內容,處理更新事件, 在這裏,其實系統還有一個方法用於更新視圖:- (void)update;
//在顯示每一個幀以前調用
- (void)glkViewControllerUpdate:(GLKViewController *)controller;
複製代碼
注: 若是不對GLKViewController進行子類化,則會調用glkViewControllerUpdate進行視圖更新,若是GLKViewController被子類化,而且手動實現了- (void)update;則此時就不會調用glkViewControllerUpdate,至關於update覆蓋了glkViewControllerUpdate,其實本質上update和glkViewControllerUpdate是相同的。
6.暫停/恢復通知
//在渲染循環暫停或者恢復以前調用
- (void)glkViewController:(GLKViewController *)controller willPause:(BOOL)pause;
複製代碼
3.GLKit 紋理加載GLTextureLoader
GLKTextureInfo類建立OpenGL紋理信息。該類包含如下屬性:
name : OpenGL上下文中紋理名稱 target : 紋理綁定的目標 height: 加載的紋理高度 width : 加載的紋理寬度 textureOrigin : 加載紋理中的原點位置 alphaState : 加載紋理中alpha份量狀態
GLTextureLoader 簡化從各類資源文件中加載紋理:
//初始化一個新的紋理加載到對象中
- (instancetype)initWithSharegroup:(EAGLSharegroup *)sharegroup;
//初始化一個新的紋理加載對象
- (instancetype)initWithShareContext:(NSOpenGLContext *)context;
複製代碼
2.從文件資源中加載紋理
//從文件加載2D紋理圖像並從數據中建立新的紋理
+ (nullable GLKTextureInfo *)textureWithContentsOfFile:(NSString *)path options:(nullable NSDictionary<NSString*, NSNumber*> *)options error:(NSError * __nullable * __nullable)outError;
//從文件中異步加載2D紋理圖像,並根據數據建立新紋理
- (void)textureWithContentsOfFile:(NSString *)path options:(nullable NSDictionary<NSString*, NSNumber*> *)options queue:(nullable dispatch_queue_t)queue completionHandler:(GLKTextureLoaderCallback)block;
複製代碼
3.從URL地址中加載紋理
//用URL加載2D紋理圖像並從數據中建立新的紋理
+ (nullable GLKTextureInfo *)textureWithContentsOfURL:(NSURL *)url options:(nullable NSDictionary<NSString*, NSNumber*> *)options error:(NSError * __nullable * __nullable)outError;
//用URL異步加載2D紋理圖像,並根據數據建立新紋理
- (void)textureWithContentsOfFile:(NSString *)path options:(nullable NSDictionary<NSString*, NSNumber*> *)options queue:(nullable dispatch_queue_t)queue completionHandler:(GLKTextureLoaderCallback)block;
複製代碼
4.從內存中數據建立紋理
//從內存空間加載2D紋理圖像並從數據中建立新的紋理
+ (nullable GLKTextureInfo *)textureWithContentsOfData:(NSData *)data options:(nullable NSDictionary<NSString*, NSNumber*> *)options error:(NSError * __nullable * __nullable)outError;
//從內存空間異步加載2D紋理圖像,並根據數據建立新紋理
- (void)textureWithContentsOfData:(NSData *)data options:(nullable NSDictionary<NSString*, NSNumber*> *)options queue:(nullable dispatch_queue_t)queue completionHandler:(GLKTextureLoaderCallback)block;
複製代碼
5.從CGImages建立紋理
//從Quartz加載2D紋理圖像並從數據中建立新的紋理
+ (nullable GLKTextureInfo *)textureWithCGImage:(CGImageRef)cgImage options:(nullable NSDictionary<NSString*, NSNumber*> *)options error:(NSError * __nullable * __nullable)outError;
//從Quartz異步加載2D紋理圖像,並根據數據建立新紋理
- (void)textureWithCGImage:(CGImageRef)cgImage options:(nullable NSDictionary<NSString*, NSNumber*> *)options queue:(nullable dispatch_queue_t)queue completionHandler:(GLKTextureLoaderCallback)block;
複製代碼
6.從URL加載多維數據建立紋理
//從單個URL加載⽴方體貼圖紋理圖像,並根據數據建立新紋理
+ (nullable GLKTextureInfo*)cubeMapWithContentsOfURL:(NSURL *)url options:(nullable NSDictionary<NSString*, NSNumber*> *)options error:(NSError * __nullable * __nullable)outError;
//從單個URL異步加載⽴方體貼圖紋理圖像,並根據數據建立新紋理
- (void)cubeMapWithContentsOfURL:(NSURL *)url options:(nullable NSDictionary<NSString*, NSNumber*> *)options queue:(nullable dispatch_queue_t)queue completionHandler:(GLKTextureLoaderCallback)block;
複製代碼
7.從文件資源加載多維數據建立紋理
//從單個文件加載⽴方體貼圖紋理對象,並從數據中建立新紋理
+ (nullable GLKTextureInfo*)cubeMapWithContentsOfFile:(NSString *)path options:(nullable NSDictionary<NSString*, NSNumber*> *)options error:(NSError * __nullable * __nullable)outError;
//從單個文件異步立方體貼圖紋理圖像,並根據數據建立新紋理
- (void)cubeMapWithContentsOfFile:(NSString *)path options:(nullable NSDictionary<NSString*, NSNumber*> *)options queue:(nullable dispatch_queue_t)queue completionHandler:(GLKTextureLoaderCallback)block;
//從一系列文件加載立方體貼圖紋理圖像.並根據數據建立新的紋理
+ (nullable GLKTextureInfo*)cubeMapWithContentsOfFiles:(NSArray<id> *)paths options:(nullable NSDictionary<NSString*, NSNumber*> *)options error:(NSError * __nullable * __nullable)outError;
//從一系列文件異步立方體貼圖紋理圖像,並根據數據建立新紋理
- (void)cubeMapWithContentsOfFiles:(NSArray<id> *)paths options:(nullable NSDictionary<NSString*, NSNumber*> *)options queue:(nullable dispatch_queue_t)queue completionHandler:(GLKTextureLoaderCallback)block;
複製代碼
4.GLKit光照GLKBaseEffect
1.命名Effect
//給Effect(效果)命名
NSString *label;
複製代碼
2.配置模型視圖轉換
//綁定效果時應用於頂點數據的模型視圖,投影和紋理變換
GLKEffectPropertyTransform *transform;
複製代碼
3.配置光照效果
//⽤於計算每一個片斷的光照策略,
GLKLightingType lightingType;
注:
GLKLightingTypePerVertex 表示在三⻆形中每一個頂點執⾏光照計算,而後在三角形進行插值。
GLKLightingTypePerPixel 表示光照計算的輸⼊在三角形內插入,而且在每一個片斷執行光照計算。
複製代碼
4.配置光照
//布爾值,表示爲基元的兩側計算光照
GLboolean lightModelTwoSided;
//計算渲染圖元光照使⽤用的材質屬性
GLKEffectPropertyMaterial *material;
//環境顏色,應⽤效果渲染的全部圖元
GLKVector4 lightModelAmbientColor;
//場景中第一個光照屬性,第二個光照屬性,第三個光照屬性
GLKEffectPropertyLight *light0, *light1, *light2;
複製代碼
5.配置紋理
//第⼀個紋理屬性,第二個紋理屬性
GLKEffectPropertyTexture *texture2d0, *texture2d1;
//紋理應⽤於渲染圖元的順序
NSArray<GLKEffectPropertyTexture*> *textureOrder;
複製代碼
6.配置霧化
//應用於場景的霧屬性
GLKEffectPropertyFog *fog;
複製代碼
7.配置顏色信息
//布爾值,表示計算光照與材質交互時是否使用顏色頂點屬性
GLboolean colorMaterialEnabled;
//布爾值,指示是否使用常量顏⾊
GLboolean useConstantColor;
//不提供每一個頂點顏色數據時使用常量顏⾊
GLKVector4 constantColor;
複製代碼
8.準備繪製效果
//準備渲染效果
- (void) prepareToDraw;
複製代碼
至此 OpenGL ES GLKit的經常使用API基本就是這些,後續還會繼續補充進來。若有書寫錯誤,註釋錯誤,方法使用錯誤還請指出。THX。