OpenGL ES背景介紹
OpenGL ES (OpenGL for Embedded Systems) 是以?手持和嵌入式為?標的?級3D圖形應用程序編程接?(API). OpenGL ES 是目前智能手機中占據(jù)統(tǒng)治地位的圖形API.?持的平臺: iOS, Andriod , BlackBerry ,bada ,Linux ,Windows.
OpenGL ES 開放式圖形庫(OpenGL的)用于可視化的?維和三維數(shù)據(jù)嗡午。它是一個多功能開放標準圖形庫,?持2D和3D數(shù)字內容創(chuàng)建柬泽,機械和建筑設計畦浓,虛擬原型設計衷掷,飛?模擬,視頻游戲等應用程序。您可以使?OpenGL配置3D圖形管道并向其提交數(shù)據(jù)浩姥。頂點被變換和點亮,組合成圖元状您,并光柵化以創(chuàng)建2D圖像勒叠。OpenGL旨在將函數(shù)調用轉換為可以發(fā)送到底層圖形硬件的圖形命令兜挨。由于此底層硬件專用于處理圖形命令,因此OpenGL繪圖通常?趁蟹郑快拌汇。
GLKit簡介
GLKit 框架的設計目標是為了簡化基于OpenGL / OpenGL ES 的應用開發(fā)。它的出現(xiàn)加快OpenGL ES或OpenGL應?程序開發(fā)昆稿。 使用數(shù)學庫纺座,背景紋理加載,預先創(chuàng)建的著色器效果溉潭,以及標準視圖和視圖控制器來實現(xiàn)渲染循環(huán)比驻。
GLKit框架提供了功能和類,可以減少創(chuàng)建新的基于著色器的應用程序所需的工作量岛抄,或者支持依賴早期版本的OpenGL ES或OpenGL提供的固定函數(shù)頂點或?段處理的現(xiàn)有應用程序别惦。
GLKit的功能:
1.加載紋理
2.提供高性能的數(shù)學運算
3.提供常?的著?器
4.提供視圖以及視圖控制器.
GLKit是Cocoa Touch以及多個其他的框架(包含UIKit)的一部分。GLKView和GLKViewController類是GLKit框架的一部分夫椭。
GLKView是Cocoa Touch UIView類的內建子類掸掸, 提供繪制場所(View);
GLKViewController是UIViewController的內建子類(擴展于標準的UIKit 設計模式. ?于繪制視圖內容的管理與呈現(xiàn).)
GLKit的Hello World
新建Xcode工程,在ViewController.h中導入頭文件
#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是否創(chuàng)建成功
if (!context) {
NSLog(@"Create ES context Failed");
}
//設置當前上下文
[EAGLContext setCurrentContext:context];
//2.獲取GLKView & 設置context
GLKView *view =(GLKView *) self.view;
view.context = context;
//3.配置視圖創(chuàng)建的渲染緩存區(qū).
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
view.drawableDepthFormat = GLKViewDrawableDepthFormat16;
//4.設置背景顏色
glClearColor(1, 0, 0, 1.0);
}
注解1:
EAGLContext 是蘋果iOS平臺下實現(xiàn)OpenGLES 渲染層.
kEAGLRenderingAPIOpenGLES1 = 1, 固定管線
kEAGLRenderingAPIOpenGLES2 = 2,
kEAGLRenderingAPIOpenGLES3 = 3,
注解2:
(1). drawableColorFormat: 顏色緩存區(qū)格式.
簡介: OpenGL ES 有一個緩存區(qū),它用以存儲將在屏幕中顯示的顏色仁讨。你可以使用其屬性來設置緩沖區(qū)中的每個像素的顏色格式羽莺。
GLKViewDrawableColorFormatRGBA8888 = 0,
默認緩存區(qū)的每個像素的最小組成部分(RGBA)使用8個bit,(所以每個像素4個字節(jié)洞豁,4*8個bit)盐固。
GLKViewDrawableColorFormatRGB565,
如果你的APP允許更小范圍的顏色,即可設置這個丈挟。會讓你的APP消耗更小的資源(內存和處理時間)
(2). drawableDepthFormat: 深度緩存區(qū)格式
GLKViewDrawableDepthFormatNone = 0,意味著完全沒有深度緩沖區(qū)
GLKViewDrawableDepthFormat16,
GLKViewDrawableDepthFormat24,
如果你要使用這個屬性(一般用于3D游戲)刁卜,你應該選擇GLKViewDrawableDepthFormat16或GLKViewDrawableDepthFormat24。這里的差別是使用GLKViewDrawableDepthFormat16將消耗更少的資源
2.加載頂點/紋理坐標數(shù)據(jù)
//1.設置頂點數(shù)組(頂點坐標,紋理坐標)
/*
紋理坐標系取值范圍[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.開辟頂點緩存區(qū)
//(1).創(chuàng)建頂點緩存區(qū)標識符ID
GLuint bufferID;
glGenBuffers(1, &bufferID);
//(2).綁定頂點緩存區(qū).(明確作用)
glBindBuffer(GL_ARRAY_BUFFER, bufferID);
//(3).將頂點數(shù)組的數(shù)據(jù)copy到頂點緩存區(qū)中(GPU顯存中)
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
//3.打開讀取通道.
//頂點坐標數(shù)據(jù)
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);
//紋理坐標數(shù)據(jù)
//打開對應attribute開關
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 3);
注解1:
頂點數(shù)組: 開發(fā)者可以選擇設定函數(shù)指針曙咽,在調用繪制方法的時候蛔趴,直接由內存?zhèn)魅腠旤c數(shù)據(jù),也就是說這部分數(shù)據(jù)之前是存儲在內存當中的例朱,被稱為頂點數(shù)組孝情。
頂點緩存區(qū): 性能更高的做法是鱼蝉,提前分配一塊顯存,將頂點數(shù)據(jù)預先傳入到顯存當中箫荡。這部分的顯存魁亦,就被稱為頂點緩存區(qū)。
注解2:
(1)在iOS中, 默認情況下菲茬,出于性能考慮,所有頂點著色器的屬性(Attribute)變量都是關閉的.
意味著,頂點數(shù)據(jù)在著色器端(服務端)是不可用的. 即使你已經(jīng)使用glBufferData方法,將頂點數(shù)據(jù)從內存拷貝到頂點緩存區(qū)中(GPU顯存中).
所以, 必須由glEnableVertexAttribArray 方法打開通道.指定訪問屬性.才能讓頂點著色器能夠訪問到從CPU復制到GPU的數(shù)據(jù).
注意: 數(shù)據(jù)在GPU端是否可見派撕,即婉弹,著色器能否讀取到數(shù)據(jù),由是否啟用了對應的屬性決定终吼,這就是glEnableVertexAttribArray的功能镀赌,允許頂點著色器讀取GPU(服務器端)數(shù)據(jù)。
(2)方法簡介
glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
功能: 上傳頂點數(shù)據(jù)到顯存的方法(設置合適的方式從buffer里面讀取數(shù)據(jù))
參數(shù)列表:
index:指定要修改的頂點屬性的索引值,例如
size:每次讀取數(shù)量际跪。(如position是由3個(x,y,z)組成商佛,而顏色是4個(r,g,b,a),紋理則是2個.)
type:指定數(shù)組中每個組件的數(shù)據(jù)類型∧反颍可用的符號常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED, 和 GL_FLOAT良姆,初始值為GL_FLOAT。
normalized:指定當被訪問時幔戏,固定點數(shù)據(jù)值是否應該被歸一化(GL_TRUE)或者直接轉換為固定點值(GL_FALSE)
stride:指定連續(xù)頂點屬性之間的偏移量玛追。如果為0,那么頂點屬性會被理解為:它們是緊密排列在一起的闲延。初始值為0
ptr:指定一個指針痊剖,指向數(shù)組中第一個頂點屬性的第一個組件,初始值為0垒玲。
3.加載紋理數(shù)據(jù)(使用GLBaseEffect)
//1.獲取紋理圖片路徑
NSString * filepath = [[NSBundle mainBundle] pathForResource:@"shiyuan1" ofType:@"jpg"];
//2.設置紋理參數(shù)
//紋理坐標原點是左下角,但是圖片顯示原點應該是左上角.
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呈現(xiàn)命令的目標。然后合愈,委托方法應該繪制視圖的內容叮贩。
*/
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
//1.清除顏色緩存區(qū)
glClear(GL_COLOR_BUFFER_BIT);
//2.準備繪制
[cEffect prepareToDraw];
//3.開始繪制
glDrawArrays(GL_TRIANGLES, 0, 6);
}
繪制結果:常用API解析
1.GLKView
GLKView 使?用OpenGL ES 繪制內容的視圖默認實現(xiàn):
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.配置幀緩存區(qū)對象
drawableColorFormat 顏?渲染緩存區(qū)格式
/*
GLKViewDrawableColorFormatRGBA8888 = 0,
GLKViewDrawableColorFormatRGB565,
GLKViewDrawableColorFormatSRGBA8888,
*/
drawableDepthFormat 深度渲染緩存區(qū)格式
/*
GLKViewDrawableDepthFormatNone = 0,
GLKViewDrawableDepthFormat16,
GLKViewDrawableDepthFormat24,
*/
drawableStencilFormat 模板渲染緩存區(qū)的格式
/*
GLKViewDrawableStencilFormatNone = 0,
GLKViewDrawableStencilFormat8,
*/
drawableMultisample 多重采樣緩存區(qū)的格式
/*
GLKViewDrawableMultisampleNone = 0,
GLKViewDrawableMultisample4X,
*/
5.幀緩存區(qū)屬性
drawableHeight 底層緩存區(qū)對象的?度(以像素為單位)
drawableWidth 底層緩存區(qū)對象的寬度(以像素為單位)
6.將底層FrameBuffer 對象綁定到OpenGL ES
- (void)bindDrawable;
7.刪除與視圖關聯(lián)的可繪制對象/刪除視圖FrameBuffer對象
- (void)deleteDrawable;
8.繪制視圖內容并將其作為新圖像對象返回
@property (readonly, strong) UIImage *snapshot;
9.布爾值(BOOL),指定視圖是否響應使得視圖內容無效的消息
@property (nonatomic) BOOL enableSetNeedsDisplay;
10.立即重繪視圖內容
- (void)display;
11.繪制視圖內容(必須實現(xiàn)代理)
//GLKViewDelegate ?用于GLKView 對象回調?方法
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect;
2. GLKViewController
GLKViewController 管理OpenGL ES 渲染循環(huán)的視圖控制器
1.視圖控制器的代理
@property (nullable, nonatomic, assign) IBOutlet id <GLKViewControllerDelegate> delegate;
2.配置視圖的幀速率
//視圖控制器調用視圖以及更新視圖內容的速率
@property (nonatomic) NSInteger preferredFramesPerSecond;
//視圖控制器調用視圖以及更新其內容的實際速率
@property (nonatomic, readonly) NSInteger framesPerSecond;
3.控制幀更新
//Bool值,渲染循環(huán)是否已暫停
@property (nonatomic, getter=isPaused) BOOL paused;
//Bool值佛析,當前程序重新激活活動狀態(tài)時視圖控制器是否自動暫停循環(huán)渲染
@property (nonatomic) BOOL pauseOnWillResignActive;
//Bool值妇汗,當前程序變?yōu)榛顒訝顟B(tài)時視圖控制器是否自動恢復呈現(xiàn)渲染
@property (nonatomic) BOOL resumeOnDidBecomeActive;
4.獲取有關視圖view的更新信息
//視圖控制器自創(chuàng)建以來發(fā)送的幀更新數(shù)
@property (nonatomic, readonly) NSInteger framesDisplayed;
//?視圖控制器第?次恢復發(fā)送更新事件以來經(jīng)過的時間量
@property (nonatomic, readonly) NSTimeInterval timeSinceFirstResume;
//自上次視圖控制器恢復發(fā)送更新事件以來更新的時間量
@property (nonatomic, readonly) NSTimeInterval timeSinceLastResume;
//?上次視圖控制器調用委托?法以及經(jīng)過的時間量
@property (nonatomic, readonly) NSTimeInterval timeSinceLastUpdate;
//?上次視圖控制器調用視圖display 方法以來經(jīng)過的時間量
@property (nonatomic, readonly) NSTimeInterval timeSinceLastDraw;
5.渲染循環(huán)回調方法--更新視圖內容,處理更新事件,
在這里说莫,其實系統(tǒng)還有一個方法用于更新視圖:- (void)update;
//在顯示每個幀之前調用
- (void)glkViewControllerUpdate:(GLKViewController *)controller;
注:
如果不對GLKViewController進行子類化杨箭,則會調用glkViewControllerUpdate進行視圖更新,如果GLKViewController被子類化储狭,并且手動實現(xiàn)了- (void)update;則此時就不會調用glkViewControllerUpdate互婿,相當于update覆蓋了glkViewControllerUpdate捣郊,其實本質上update和glkViewControllerUpdate是相同的。
6.暫停/恢復通知
//在渲染循環(huán)暫痛炔危或者恢復之前調用
- (void)glkViewController:(GLKViewController *)controller willPause:(BOOL)pause;
3.GLKit 紋理加載GLTextureLoader
GLKTextureInfo類創(chuàng)建OpenGL紋理信息呛牲。該類包含以下屬性:
name : OpenGL上下文中紋理名稱
target : 紋理綁定的目標
height: 加載的紋理高度
width : 加載的紋理寬度
textureOrigin : 加載紋理中的原點位置
alphaState : 加載紋理中alpha分量狀態(tài)
GLTextureLoader 簡化從各種資源文件中加載紋理:
- 初始化
//初始化一個新的紋理加載到對象中
- (instancetype)initWithSharegroup:(EAGLSharegroup *)sharegroup;
//初始化一個新的紋理加載對象
- (instancetype)initWithShareContext:(NSOpenGLContext *)context;
2.從文件資源中加載紋理
//從文件加載2D紋理圖像并從數(shù)據(jù)中創(chuàng)建新的紋理
+ (nullable GLKTextureInfo *)textureWithContentsOfFile:(NSString *)path options:(nullable NSDictionary<NSString*, NSNumber*> *)options error:(NSError * __nullable * __nullable)outError;
//從文件中異步加載2D紋理圖像,并根據(jù)數(shù)據(jù)創(chuàng)建新紋理
- (void)textureWithContentsOfFile:(NSString *)path options:(nullable NSDictionary<NSString*, NSNumber*> *)options queue:(nullable dispatch_queue_t)queue completionHandler:(GLKTextureLoaderCallback)block;
3.從URL地址中加載紋理
//用URL加載2D紋理圖像并從數(shù)據(jù)中創(chuàng)建新的紋理
+ (nullable GLKTextureInfo *)textureWithContentsOfURL:(NSURL *)url options:(nullable NSDictionary<NSString*, NSNumber*> *)options error:(NSError * __nullable * __nullable)outError;
//用URL異步加載2D紋理圖像驮配,并根據(jù)數(shù)據(jù)創(chuàng)建新紋理
- (void)textureWithContentsOfFile:(NSString *)path options:(nullable NSDictionary<NSString*, NSNumber*> *)options queue:(nullable dispatch_queue_t)queue completionHandler:(GLKTextureLoaderCallback)block;
4.從內存中數(shù)據(jù)創(chuàng)建紋理
//從內存空間加載2D紋理圖像并從數(shù)據(jù)中創(chuàng)建新的紋理
+ (nullable GLKTextureInfo *)textureWithContentsOfData:(NSData *)data options:(nullable NSDictionary<NSString*, NSNumber*> *)options error:(NSError * __nullable * __nullable)outError;
//從內存空間異步加載2D紋理圖像娘扩,并根據(jù)數(shù)據(jù)創(chuàng)建新紋理
- (void)textureWithContentsOfData:(NSData *)data options:(nullable NSDictionary<NSString*, NSNumber*> *)options queue:(nullable dispatch_queue_t)queue completionHandler:(GLKTextureLoaderCallback)block;
5.從CGImages創(chuàng)建紋理
//從Quartz加載2D紋理圖像并從數(shù)據(jù)中創(chuàng)建新的紋理
+ (nullable GLKTextureInfo *)textureWithCGImage:(CGImageRef)cgImage options:(nullable NSDictionary<NSString*, NSNumber*> *)options error:(NSError * __nullable * __nullable)outError;
//從Quartz異步加載2D紋理圖像,并根據(jù)數(shù)據(jù)創(chuàng)建新紋理
- (void)textureWithCGImage:(CGImageRef)cgImage options:(nullable NSDictionary<NSString*, NSNumber*> *)options queue:(nullable dispatch_queue_t)queue completionHandler:(GLKTextureLoaderCallback)block;
6.從URL加載多維數(shù)據(jù)創(chuàng)建紋理
//從單個URL加載?方體貼圖紋理圖像,并根據(jù)數(shù)據(jù)創(chuàng)建新紋理
+ (nullable GLKTextureInfo*)cubeMapWithContentsOfURL:(NSURL *)url options:(nullable NSDictionary<NSString*, NSNumber*> *)options error:(NSError * __nullable * __nullable)outError;
//從單個URL異步加載?方體貼圖紋理圖像,并根據(jù)數(shù)據(jù)創(chuàng)建新紋理
- (void)cubeMapWithContentsOfURL:(NSURL *)url options:(nullable NSDictionary<NSString*, NSNumber*> *)options queue:(nullable dispatch_queue_t)queue completionHandler:(GLKTextureLoaderCallback)block;
7.從文件資源加載多維數(shù)據(jù)創(chuàng)建紋理
//從單個文件加載?方體貼圖紋理對象,并從數(shù)據(jù)中創(chuàng)建新紋理
+ (nullable GLKTextureInfo*)cubeMapWithContentsOfFile:(NSString *)path options:(nullable NSDictionary<NSString*, NSNumber*> *)options error:(NSError * __nullable * __nullable)outError;
//從單個文件異步立方體貼圖紋理圖像壮锻,并根據(jù)數(shù)據(jù)創(chuàng)建新紋理
- (void)cubeMapWithContentsOfFile:(NSString *)path options:(nullable NSDictionary<NSString*, NSNumber*> *)options queue:(nullable dispatch_queue_t)queue completionHandler:(GLKTextureLoaderCallback)block;
//從一系列文件加載立方體貼圖紋理圖像.并根據(jù)數(shù)據(jù)創(chuàng)建新的紋理
+ (nullable GLKTextureInfo*)cubeMapWithContentsOfFiles:(NSArray<id> *)paths options:(nullable NSDictionary<NSString*, NSNumber*> *)options error:(NSError * __nullable * __nullable)outError;
//從一系列文件異步立方體貼圖紋理圖像琐旁,并根據(jù)數(shù)據(jù)創(chuàng)建新紋理
- (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.配置模型視圖轉換
//綁定效果時應用于頂點數(shù)據(jù)的模型視圖,投影和紋理變換
GLKEffectPropertyTransform *transform;
3.配置光照效果
//?于計算每個片段的光照策略,
GLKLightingType lightingType;
注:
GLKLightingTypePerVertex 表示在三?形中每個頂點執(zhí)?光照計算,然后在三角形進行插值猜绣。
GLKLightingTypePerPixel 表示光照計算的輸?在三角形內插入,并且在每個片段執(zhí)行光照計算灰殴。
4.配置光照
//布爾值,表示為基元的兩側計算光照
GLboolean lightModelTwoSided;
//計算渲染圖元光照使?用的材質屬性
GLKEffectPropertyMaterial *material;
//環(huán)境顏色,應?效果渲染的所有圖元
GLKVector4 lightModelAmbientColor;
//場景中第一個光照屬性,第二個光照屬性掰邢,第三個光照屬性
GLKEffectPropertyLight *light0, *light1, *light2;
5.配置紋理
//第?個紋理屬性牺陶,第二個紋理屬性
GLKEffectPropertyTexture *texture2d0, *texture2d1;
//紋理應?于渲染圖元的順序
NSArray<GLKEffectPropertyTexture*> *textureOrder;
6.配置霧化
//應用于場景的霧屬性
GLKEffectPropertyFog *fog;
7.配置顏色信息
//布爾值,表示計算光照與材質交互時是否使用顏色頂點屬性
GLboolean colorMaterialEnabled;
//布爾值,指示是否使用常量顏?
GLboolean useConstantColor;
//不提供每個頂點顏色數(shù)據(jù)時使用常量顏?
GLKVector4 constantColor;
8.準備繪制效果
//準備渲染效果
- (void) prepareToDraw;
至此 OpenGL ES GLKit的常用API基本就是這些,后續(xù)還會繼續(xù)補充進來辣之。如有書寫錯誤掰伸,注釋錯誤,方法使用錯誤還請指出怀估。THX碱工。