OpenGL ES for iOS - 3

繪制OpenGL ES和GLKit

GLKit框架提供視圖和視圖控制器類,可以消除為繪制和動畫化OpenGL ES內(nèi)容而需要的設(shè)置和維護代碼。 GLKView類管理OpenGL ES基礎(chǔ)架構(gòu),為您的繪圖代碼提供一個地方,GLKViewController類為GLKit視圖中OpenGL ES內(nèi)容的平滑動畫提供了一個渲染循環(huán)。這些類擴展了用于繪制視圖內(nèi)容和管理視圖呈現(xiàn)的標準UIKit設(shè)計模式。因此,您可以將重點放在OpenGL ES渲染代碼上,并使您的應(yīng)用程序快速啟動并運行。 GLKit框架還提供了其他功能來簡化OpenGL ES 2.0和3.0開發(fā)。

GLKit視圖根據(jù)需要繪制OpenGL ES內(nèi)容

GLKView類提供與標準UIView繪圖周期相當?shù)腛penGL ES。 UIView實例自動配置其圖形上下文,以便您的drawRect:實現(xiàn)只需要執(zhí)行Quartz 2D繪圖命令,并且GLKView實例自動配置,以便您的繪圖方法只需執(zhí)行OpenGL ES繪圖命令。 GLKView類通過維護保存OpenGL ES繪圖命令結(jié)果的framebuffer對象來提供此功能,然后在繪圖方法返回后自動將其顯示給Core Animation。

像標準的UIKit視圖一樣,GLKit視圖根據(jù)需要呈現(xiàn)其內(nèi)容。當您的視圖第一次顯示時,它會調(diào)用您的繪圖方法 - Core Animation緩存渲染的輸出,并在顯示視圖時顯示它。當您想要更改視圖的內(nèi)容時,請調(diào)用其setNeedsDisplay方法,再次調(diào)用繪圖方法,緩存生成的圖像,并將其顯示在屏幕上。當用于渲染圖像的數(shù)據(jù)不經(jīng)常更改或僅響應(yīng)于用戶操作時,此方法非常有用。通過僅在需要時才提供新的視圖內(nèi)容,您可以節(jié)省設(shè)備上的電池電量,并為設(shè)備執(zhí)行其他操作留出更多時間


3-1.png

創(chuàng)建和配置GLKit視圖

您可以以編程方式或使用Interface Builder創(chuàng)建和配置GLKView對象。在使用它繪制之前,必須將其與EAGLContext對象相關(guān)聯(lián)(請參閱配置OpenGL ES上下文)。

  • 以編程方式創(chuàng)建視圖時,首先創(chuàng)建上下文,然后將其傳遞給視圖的initWithFrame:context:方法。
  • 從故事板加載視圖后,創(chuàng)建上下文并將其設(shè)置為視圖的上下文屬性的值。

GLKit視圖會自動創(chuàng)建和配置自己的OpenGL ES framebuffer對象和renderbuffers。您可以使用視圖的可繪制屬性來控制這些對象的屬性,如清單3-1所示。如果更改GLKit視圖的大小,比例因子或可繪制屬性,則會在下次繪制內(nèi)容時自動刪除并重新創(chuàng)建相應(yīng)的framebuffer對象和renderbuffers。
Listing3-1

- (void)viewDidLoad
{
    [super viewDidLoad];
 
    // Create an OpenGL ES context and assign it to the view loaded from storyboard
    GLKView *view = (GLKView *)self.view;
    view.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
 
    // Configure renderbuffers created by the view
    view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
    view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
    view.drawableStencilFormat = GLKViewDrawableStencilFormat8;
 
    // Enable multisampling
    view.drawableMultisample = GLKViewDrawableMultisample4X;
}

您可以使用其drawableMultisample屬性為GLKView實例啟用多采樣。多采樣是一種抗鋸齒形式,可以平滑鋸齒狀邊緣,以更多的內(nèi)存和片段處理時間為代價,以大多數(shù)3D應(yīng)用程序的圖像質(zhì)量提升,如果啟用多采樣,則始終測試應(yīng)用程序的性能,以確保其仍然可以接受。

繪制GLKit視圖

圖3-1概述了繪制OpenGL ES內(nèi)容的三個步驟:準備OpenGL ES基礎(chǔ)設(shè)施,發(fā)布繪圖命令,并將呈現(xiàn)的內(nèi)容呈現(xiàn)給Core Animation進行顯示。 GLKView類實現(xiàn)了第一和第三步。對于第二步,您將實現(xiàn)一個繪圖方法,如清單3-2中的示例所示。
Listing3-2

- (void)drawRect:(CGRect)rect
{
    // Clear the framebuffer
    glClearColor(0.0f, 0.0f, 0.1f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
    // Draw using previously configured texture, shader, uniforms, and vertex array
    glBindTexture(GL_TEXTURE_2D, _planetTexture);
    glUseProgram(_diffuseShading);
    glUniformMatrix4fv(_uniformModelViewProjectionMatrix, 1, 0, _modelViewProjectionMatrix.m);
    glBindVertexArrayOES(_planetMesh);
    glDrawElements(GL_TRIANGLE_STRIP, 256, GL_UNSIGNED_SHORT);
}

注意:glClear函數(shù)提示OpenGL ES可以丟棄任何現(xiàn)有的幀緩沖區(qū)內(nèi)容,避免了昂貴的內(nèi)存操作將以前的內(nèi)容加載到內(nèi)存中。為了確保最佳性能,您應(yīng)該在繪制之前始終調(diào)用此函數(shù)。

GLKView類能夠為OpenGL ES繪圖提供一個簡單的界面,因為它可以管理OpenGL ES渲染過程的標準部分

  • 在調(diào)用繪圖方法之前,該視圖:
  • 使其EAGLContext對象成為當前上下文
  • 根據(jù)當前大小,比例因子和可繪制屬性(如果需要)創(chuàng)建一個framebuffer對象和renderbuffers
  • 將framebuffer對象綁定為繪制命令的當前目標
  • 設(shè)置OpenGL ES視口以匹配幀緩沖區(qū)大小
  • 在您的繪圖方法返回后,視圖:
  • 解決多采樣緩沖區(qū)(如果啟用了多次采樣)
  • 丟棄其內(nèi)容不再需要的renderbuffers
  • 向Core Animation呈現(xiàn)renderbuffer內(nèi)容以進行緩存和顯示

使用委托對象呈現(xiàn)

許多OpenGL ES應(yīng)用程序在自定義類中實現(xiàn)渲染代碼。這種方法的優(yōu)點在于它允許您通過為每個渲染算法定義不同的渲染器類來輕松支持多種渲染算法。共享公共功能的渲染算法可以從超類繼承。例如,您可以使用不同的渲染器類來支持OpenGL ES 2.0和3.0(請參閱配置OpenGL ES上下文)。或者您可以使用它們來定制渲染,從而在具有更強大硬件的設(shè)備上獲得更好的圖像質(zhì)量

GLKit非常適合這種方法 - 您可以使您的渲染器對象成為標準GLKView實例的委托。您的渲染器類不是將GLKView子類化并實現(xiàn)drawRect:方法,而是使用GLKViewDelegate協(xié)議并實現(xiàn)glkView:drawInRect:方法。程序清單3-3演示了在應(yīng)用程序啟動時基于硬件功能選擇渲染器類
Listing3-3

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Create a context so we can test for features
    EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    [EAGLContext setCurrentContext:context];
 
    // Choose a rendering class based on device features
    GLint maxTextureSize;
    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
    if (maxTextureSize > 2048)
        self.renderer = [[MyBigTextureRenderer alloc] initWithContext:context];
    else
        self.renderer = [[MyRenderer alloc] initWithContext:context];
 
    // Make the renderer the delegate for the view loaded from the main storyboard
    GLKView *view = (GLKView *)self.window.rootViewController.view;
    view.delegate = self.renderer;
 
    // Give the OpenGL ES context to the view so it can draw
    view.context = context;
 
    return YES;
}

GLKit視圖控制器動畫化OpenGL ES內(nèi)容

默認情況下,GLKView對象根據(jù)需要呈現(xiàn)其內(nèi)容。也就是說,使用OpenGL ES繪制的一個關(guān)鍵優(yōu)點是它能夠使用圖形處理硬件來連續(xù)制作復(fù)雜場景 - 諸如游戲和模擬等應(yīng)用程序很少呈現(xiàn)靜態(tài)圖像。對于這些情況,GLKit框架提供了一個視圖控制器類,它為其管理的GLKView對象維護一個動畫循環(huán)。該循環(huán)遵循游戲和模擬中常見的設(shè)計模式,分為兩個階段:更新和顯示。圖3-2顯示了動畫循環(huán)的簡化示例。

3-2.png

了解動畫循環(huán)
對于更新階段,視圖控制器調(diào)用其自己的更新方法(或其委托的glkViewControllerUpdate:方法)。在這種方法中,你應(yīng)該準備繪制下一幀。例如,游戲可能會使用這種方法根據(jù)自最后一幀以來接收到的輸入事件來確定玩家和敵人角色的位置,科學(xué)可視化可能會使用此方法來運行其模擬步驟。如果您需要時間信息來確定應(yīng)用的下一幀的狀態(tài),請使用其中一個視圖控制器的時間屬性,如timeSinceLastUpdate屬性。在圖3-2中,更新階段增加一個角度變量,并使用它來計算變換矩陣。

對于顯示階段,視圖控制器調(diào)用其視圖的顯示方法,該方法又調(diào)用您的繪圖方法。在繪圖方法中,您可以向GPU提交OpenGL ES繪圖命令以呈現(xiàn)內(nèi)容。為了獲得最佳性能,您的應(yīng)用程序應(yīng)在渲染新幀時開始修改OpenGL ES對象,之后提交繪圖命令。在圖3-2中,顯示階段將著色器程序中的均勻變量設(shè)置為在更新階段計算的矩陣,然后提交繪圖命令以呈現(xiàn)新內(nèi)容。

動畫循環(huán)按照視圖控制器的framePerSecond屬性指示的速率在這兩個階段之間進行交替。您可以使用preferredFramesPerSecond屬性設(shè)置所需的幀速率,以優(yōu)化當前顯示硬件的性能,視圖控制器會自動選擇接近您的首選值的最佳幀速率。

重要提示:為獲得最佳效果,請選擇應(yīng)用程序可以始終如一地實現(xiàn)的幀率平滑,一致的幀速率產(chǎn)生比不規(guī)則變化的幀速率更愉快的用戶體驗。

使用GLKit視圖控制器

清單3-4演示了使用GLKViewController子類和GLKView實例渲染動畫OpenGL ES內(nèi)容的典型策略。

@implementation PlanetViewController // subclass of GLKViewController
 
- (void)viewDidLoad
{
    [super viewDidLoad];
 
    // Create an OpenGL ES context and assign it to the view loaded from storyboard
    GLKView *view = (GLKView *)self.view;
    view.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
 
    // Set animation frame rate
    self.preferredFramesPerSecond = 60;
 
    // Not shown: load shaders, textures and vertex arrays, set up projection matrix
    [self setupGL];
}
 
- (void)update
{
    _rotation += self.timeSinceLastUpdate * M_PI_2; // one quarter rotation per second
 
    // Set up transform matrices for the rotating planet
    GLKMatrix4 modelViewMatrix = GLKMatrix4MakeRotation(_rotation, 0.0f, 1.0f, 0.0f);
    _normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(modelViewMatrix), NULL);
    _modelViewProjectionMatrix = GLKMatrix4Multiply(_projectionMatrix, modelViewMatrix);
}
 
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    // Clear the framebuffer
    glClearColor(0.0f, 0.0f, 0.1f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
    // Set shader uniforms to values calculated in -update
    glUseProgram(_diffuseShading);
    glUniformMatrix4fv(_uniformModelViewProjectionMatrix, 1, 0, _modelViewProjectionMatrix.m);
    glUniformMatrix3fv(_uniformNormalMatrix, 1, 0, _normalMatrix.m);
 
    // Draw using previously configured texture and vertex array
    glBindTexture(GL_TEXTURE_2D, _planetTexture);
    glBindVertexArrayOES(_planetMesh);
    glDrawElements(GL_TRIANGLE_STRIP, 256, GL_UNSIGNED_SHORT, 0);
}
 
@end

在此示例中,PlanetViewController類(自定義GLKViewController子類)的實例從故事板加載,以及標準GLKView實例及其可繪制屬性。 viewDidLoad方法創(chuàng)建一個OpenGL ES上下文并將其提供給視圖,并且還設(shè)置動畫循環(huán)的幀速率。

視圖控制器自動地代表其視圖,因此它實現(xiàn)了動畫循環(huán)的更新和顯示階段。在更新方法中,它計算顯示旋轉(zhuǎn)行星所需的變換矩陣。在glkView:drawInRect:方法中,它將這些矩陣提供給著色器程序,并提交繪圖命令來渲染行星幾何。

使用GLKit開發(fā)您的渲染器

除了查看和查看控制器基礎(chǔ)設(shè)施外,GLKit框架還提供了幾個其他功能來簡化iOS上的OpenGL ES開發(fā)。

處理矢量和矩陣數(shù)學(xué)
OpenGL ES 2.0及更高版本不提供用于創(chuàng)建或指定變換矩陣的內(nèi)置函數(shù)。相反,可編程著色器提供頂點變換,并使用通用的均勻變量指定著色器輸入。 GLKit框架包括矢量和矩陣類型和功能的綜合庫,針對iOS硬件上的高性能進行了優(yōu)化。 (見GLKit框架參考。)

從OpenGL ES 1.1固定功能管道遷移
OpenGL ES 2.0及更高版本刪除與OpenGL ES 1.1固定功能圖形管道相關(guān)聯(lián)的所有功能。 GLKBaseEffect類為OpenGL ES 1.1流水線的轉(zhuǎn)換,照明和陰影階段提供了Objective-C模擬,GLKSkyboxEffect和GLKReflectionMapEffect類增加了對常見視覺效果的支持。有關(guān)詳細信息,請參閱這些類的參考文檔。

加載紋理數(shù)據(jù)
GLKTextureLoader類提供了一種簡單的方法來將紋理數(shù)據(jù)從iOS支持的任何圖像格式加載到OpenGL ES上下文中,同步或異步。 (請參閱使用GLKit框架加載紋理數(shù)據(jù)。)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,208評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,746評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,666評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,477評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,960評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,200評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,726評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,617評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,807評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,049評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,425評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,674評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,432評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,769評論 2 372

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