OpenGL ES 入門之旅(10)--OpenGL ES快速瞭解GLKit

OpenGL ES背景介紹

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的簡化版本,它消除了了冗餘功能,提供了一個既易於學習又更易於在移動圖形硬件中實現的庫。設計模式

OpenGL ES.png
OpenGL ES容許應用程序利用底層圖形處理器的強大功能。iOS設備上的GPU能夠執行復雜的2D和3D繪圖,以及最終圖像中每一個像素的複雜着⾊計算。

GLKit簡介

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 設計模式. ⽤於繪製視圖內容的管理與呈現.)緩存

GLKit的Hello World

新建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);  
}
複製代碼

繪製結果:

繪製結果.png
下面用思惟導圖的形式作個OpenGL ES GLKit 加載圖片的總結:
思惟導圖.png

經常使用API解析

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 簡化從各類資源文件中加載紋理:

  1. 初始化
//初始化一個新的紋理加載到對象中
- (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。

相關文章
相關標籤/搜索