iOS開發(fā)之OpenGL ES(二) —— 快速了解并使用GLKit

前言

這篇文章的目的是為了快速了解GLKit,并使用它實現(xiàn)一個簡單的加載圖片的小功能秽荞。

什么是GLKit?

  • GLKit 框架的設(shè)計?標(biāo)是為了簡化基于OpenGL / OpenGL ES 的應(yīng)?開發(fā). 它的出現(xiàn)
    加快OpenGL ES或OpenGL應(yīng)用程序開發(fā)。 使?數(shù)學(xué)庫榆俺,背景紋理加載趴梢,預(yù)先創(chuàng)建的著
    色?效果,以及標(biāo)準(zhǔn)視圖和視圖控制?來實現(xiàn)渲染循環(huán)笑窜。
  • GLKit框架提供了功能和類藐鹤,可以減少創(chuàng)建新的基于著??的應(yīng)用程序所需的?作量瓤檐,或者支持依賴早期版本的OpenGL ES或OpenGL提供的固定函數(shù)頂點或片段處理的現(xiàn)有應(yīng)用程序。

GLKit的主要功能

  1. 加載紋理(Texture loading):** GLKTextuerLoader Class**娱节。紋理加載允許您的應(yīng)用程序輕松地從各種來源加載紋理挠蛉。 甚至可以在背景中使用幾行代碼來異步加載紋理。
  2. 性能卓越的科學(xué)運算庫肄满, 支持矢量谴古, 四元數(shù),矩陣運算等稠歉。數(shù)學(xué)庫提供常用的矢量掰担,四元數(shù)和矩陣運算。 這些實現(xiàn)被優(yōu)化以提供出色的性能怒炸。
  3. 提供常見的著色器带饱,實現(xiàn)常見的標(biāo)準(zhǔn)Shader特效。 GLKit允許你配置你所需要的特效阅羹,它會自動創(chuàng)建和加載對應(yīng)的Shader勺疼。GLKBaseEffect, GLKReflectionMapEffect, GLKSkyboxEffect Class
  4. 提供GLKit的View和ViewController捏鱼。GLKView ClassGLKViewController Class执庐。

使用GLKit在屏幕上加載一張圖片

1.準(zhǔn)備工作

導(dǎo)入相關(guān)文件

    #import <GLKit/GLKit.h>
    #import <OpenGLES/ES3/gl.h>
    #import <OpenGLES/ES3/glext.h>

使當(dāng)前的viewController繼承GLKViewController
在viewDidLoad()方法中,

 //OpenGL ES初始化
    [self setUpConfig];
    
    //2.加載頂點/紋理坐標(biāo)數(shù)據(jù)
    [self setUpVertexData];
  
     //3.加載紋理數(shù)據(jù)(使用GLBaseEffect)
    [self setUpTexture];

2.初始化OpenGL ES

代碼如下所示导梆,初始化上下文->獲取GLKView和設(shè)置上下文->配置視圖創(chuàng)建的渲染緩存區(qū)->設(shè)置背景顏色

-(void)setUpConfig
{
    //1.初始化上下文&設(shè)置當(dāng)前上下文
    /*
     EAGLContext 是蘋果iOS平臺下實現(xiàn)OpenGLES 渲染層.
     kEAGLRenderingAPIOpenGLES1 = 1, 固定管線
     kEAGLRenderingAPIOpenGLES2 = 2,
     kEAGLRenderingAPIOpenGLES3 = 3,
     */
    context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
    //判斷context是否創(chuàng)建成功
    if (!context) {
        NSLog(@"Create ES context Failed");
    }
    //設(shè)置當(dāng)前上下文
    [EAGLContext setCurrentContext:context];
    
    //2.獲取GLKView & 設(shè)置context
    GLKView * view = (GLKView *)self.view;
    view.context = context;
    
    /*3.配置視圖創(chuàng)建的渲染緩存區(qū).
     
     (1). drawableColorFormat: 顏色緩存區(qū)格式.
     簡介:  OpenGL ES 有一個緩存區(qū)轨淌,它用以存儲將在屏幕中顯示的顏色。你可以使用其屬性來設(shè)置緩沖區(qū)中的每個像素的顏色格式看尼。
     
     GLKViewDrawableColorFormatRGBA8888 = 0,
     默認(rèn).緩存區(qū)的每個像素的最小組成部分(RGBA)使用8個bit递鹉,(所以每個像素4個字節(jié),4*8個bit)狡忙。
     
     GLKViewDrawableColorFormatRGB565,
     如果你的APP允許更小范圍的顏色梳虽,即可設(shè)置這個。會讓你的APP消耗更小的資源(內(nèi)存和處理時間)
     
     (2). drawableDepthFormat: 深度緩存區(qū)格式
     
     GLKViewDrawableDepthFormatNone = 0,意味著完全沒有深度緩沖區(qū)
     GLKViewDrawableDepthFormat16,
     GLKViewDrawableDepthFormat24,
     如果你要使用這個屬性(一般用于3D游戲)灾茁,你應(yīng)該選擇GLKViewDrawableDepthFormat16
     或GLKViewDrawableDepthFormat24窜觉。這里的差別是使用GLKViewDrawableDepthFormat16
     將消耗更少的資源
     
     */
    view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
    view.drawableDepthFormat = GLKViewDrawableDepthFormat16;
    
    //4.設(shè)置背景顏色
    glClearColor(1, 0, 0, 1.0);
}

3.加載頂點/紋理坐標(biāo)數(shù)據(jù)

代碼如下所示,設(shè)置包含頂點和紋理坐標(biāo)的頂點數(shù)組->開辟頂點緩存區(qū)->分別從不同的通道中讀取頂點坐標(biāo)數(shù)據(jù)和紋理坐標(biāo)數(shù)據(jù)

-(void)setUpVertexData
{
    //1.設(shè)置頂點數(shù)組(頂點坐標(biāo),紋理坐標(biāo))
    /*
     紋理坐標(biāo)系取值范圍[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, //左下
    };
    
    /*
     頂點數(shù)組: 開發(fā)者可以選擇設(shè)定函數(shù)指針北专,在調(diào)用繪制方法的時候禀挫,直接由內(nèi)存?zhèn)魅腠旤c數(shù)據(jù),也就是說這部分?jǐn)?shù)據(jù)之前是存儲在內(nèi)存當(dāng)中的拓颓,被稱為頂點數(shù)組
     
     頂點緩存區(qū): 性能更高的做法是语婴,提前分配一塊顯存,將頂點數(shù)據(jù)預(yù)先傳入到顯存當(dāng)中。這部分的顯存砰左,就被稱為頂點緩沖區(qū)
     */
    
    //2.開辟頂點緩存區(qū)
    //(1).創(chuàng)建頂點緩存區(qū)標(biāo)識符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.打開讀取通道.
    /*
     (1)在iOS中, 默認(rèn)情況下匿醒,出于性能考慮,所有頂點著色器的屬性(Attribute)變量都是關(guān)閉的.
     意味著,頂點數(shù)據(jù)在著色器端(服務(wù)端)是不可用的. 即使你已經(jīng)使用glBufferData方法,將頂點數(shù)據(jù)從內(nèi)存拷貝到頂點緩存區(qū)中(GPU顯存中).
     所以, 必須由glEnableVertexAttribArray 方法打開通道.指定訪問屬性.才能讓頂點著色器能夠訪問到從CPU復(fù)制到GPU的數(shù)據(jù).
     注意: 數(shù)據(jù)在GPU端是否可見缠导,即廉羔,著色器能否讀取到數(shù)據(jù),由是否啟用了對應(yīng)的屬性決定僻造,這就是glEnableVertexAttribArray的功能憋他,允許頂點著色器讀取GPU(服務(wù)器端)數(shù)據(jù)。
     
     (2)方法簡介
     glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
     
     功能: 上傳頂點數(shù)據(jù)到顯存的方法(設(shè)置合適的方式從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,指定當(dāng)被訪問時旧巾,固定點數(shù)據(jù)值是否應(yīng)該被歸一化(GL_TRUE)或者直接轉(zhuǎn)換為固定點值(GL_FALSE)
     stride,指定連續(xù)頂點屬性之間的偏移量耸序。如果為0,那么頂點屬性會被理解為:它們是緊密排列在一起的鲁猩。初始值為0
     ptr指定一個指針,指向數(shù)組中第一個頂點屬性的第一個組件罢坝。初始值為0
     */
    
     //頂點坐標(biāo)數(shù)據(jù)
    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, 0);
    
    //紋理坐標(biāo)數(shù)據(jù)
    glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, (GLfloat *)NULL + 3);
    
}

需要注意廓握,在這行代碼中glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, (GLfloat *)NULL + 3)
最后一個參數(shù)是ptr,指向數(shù)組中開始讀取紋理坐標(biāo)的第一個點嘁酿,這里是指針隙券,所以指向的是內(nèi)存地址中的位置,所以這里參數(shù)寫的不是vertexData[3]闹司。

4.加載頂點/紋理坐標(biāo)數(shù)據(jù)

代碼如下所示娱仔,獲取紋理圖片路徑->設(shè)置紋理參數(shù)->使用GLKBaseEffect完成頂點和片元著色器工作

-(void)setUpTexture
{
    //1.獲取紋理圖片路徑
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"beauty" ofType:@"jpeg"];
    
    //2.設(shè)置紋理參數(shù)
    //紋理坐標(biāo)原點是左下角,但是圖片顯示原點應(yīng)該是左上角.
    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;
    
}

在這段代碼中的第二步奖地,設(shè)置了GLKTextureLoaderOriginBottomLeft墓塌,是為了解決圖片的旋轉(zhuǎn)問題,如果不設(shè)置這個參數(shù)衡楞,會發(fā)現(xiàn)圖片加載后是倒過來的借卧。

GLTextureLoader 簡化從各種資源文件中加載紋理.
從CGImages創(chuàng)建紋理理

    • textureWithCGImage:options:error: 從Quartz圖像 加載2D紋理圖像并從數(shù)據(jù)創(chuàng)
      建新紋理
    • textureWithCGImage:options:queue:completionHandler: 從Quartz圖像異步
      加載2D紋理圖像,并根據(jù)數(shù)據(jù)創(chuàng)建新紋理.

從URL加載多維創(chuàng)建紋理

    • cabeMapWithContentsOfURL:options:errer: 從單個URL加載?方體貼圖紋理
      圖像,并根據(jù)數(shù)據(jù)創(chuàng)建新紋理
    • cabeMapWithContentsOfURL:options:queue:completionHandler:從單個
      URL異步加載?方體貼圖紋理圖像,并根據(jù)數(shù)據(jù)創(chuàng)建新紋理

從?件加載多維數(shù)據(jù)創(chuàng)建紋理

    • cubeMapWithContentsOfFile:options:errer: 從單個?件加載?方體貼圖紋理理

對象,并從數(shù)據(jù)中創(chuàng)建新紋理

    • cubeMapWithContentsOfFile:options:queue:completionHandler:從單個?文件異步加載?方體貼圖紋理對象,并從數(shù)據(jù)中創(chuàng)建新紋理
    • cubeMapWithContentsOfFiles:options:errer: 從一系列?件中加載立?體貼圖
      紋理圖像,并從數(shù)據(jù)中創(chuàng)建新紋理
  • -cubeMapWithContentsOfFiles:options:queue:completionHandler:
    從?系列?件異步加載?方體貼圖紋理圖像,并從數(shù)據(jù)中創(chuàng)建新紋理

5.繪制視圖的內(nèi)容

這個方法是必須要實現(xiàn)的盹憎,用來繪制圖像

/*
 GLKView對象使其OpenGL ES上下文成為當(dāng)前上下文,并將其framebuffer綁定為OpenGL ES呈現(xiàn)命令的目標(biāo)铐刘。然后陪每,委托方法應(yīng)該繪制視圖的內(nèi)容。
*/
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    //1.清除顏色緩沖區(qū)
    glClear(GL_COLOR_BUFFER_BIT);
    
    //2.準(zhǔn)備繪制
    [cEffect prepareToDraw];
    
    //3.開始繪制
    glDrawArrays(GL_TRIANGLES, 0, 6);
}

6.運行結(jié)果

如下圖所示


GLKit 加載圖片

快速使用GLKit Demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市檩禾,隨后出現(xiàn)的幾起案子挂签,更是在濱河造成了極大的恐慌,老刑警劉巖盼产,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饵婆,死亡現(xiàn)場離奇詭異,居然都是意外死亡辆飘,警方通過查閱死者的電腦和手機啦辐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蜈项,“玉大人芹关,你說我怎么就攤上這事〗糇洌” “怎么了侥衬?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長跑芳。 經(jīng)常有香客問我轴总,道長,這世上最難降的妖魔是什么博个? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任怀樟,我火速辦了婚禮,結(jié)果婚禮上盆佣,老公的妹妹穿的比我還像新娘往堡。我一直安慰自己,他們只是感情好共耍,可當(dāng)我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布虑灰。 她就那樣靜靜地躺著,像睡著了一般痹兜。 火紅的嫁衣襯著肌膚如雪穆咐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天字旭,我揣著相機與錄音对湃,去河邊找鬼。 笑死谐算,一個胖子當(dāng)著我的面吹牛熟尉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播洲脂,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼斤儿,長吁一口氣:“原來是場噩夢啊……” “哼剧包!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起往果,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤疆液,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后陕贮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體堕油,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年肮之,在試婚紗的時候發(fā)現(xiàn)自己被綠了掉缺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡戈擒,死狀恐怖眶明,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情筐高,我是刑警寧澤搜囱,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站柑土,受9級特大地震影響蜀肘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜稽屏,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一扮宠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧狐榔,春花似錦涵卵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽典鸡。三九已至被廓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間萝玷,已是汗流浹背嫁乘。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留球碉,地道東北人蜓斧。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像睁冬,于是被迫代替她去往敵國和親挎春。 傳聞我的和親對象是個殘疾皇子看疙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容