用OpenGL ES and GLKit繪制 譯文

GLKit框架提供的視圖和視圖控制器類(消除了 OpenGL ES繪圖和動畫內(nèi)容要求的安裝和維護的代碼)仰泻。GLKView類管理的OpenGL ES的基礎(chǔ)設(shè)施 提供書寫繪圖代碼的地方佩捞,GLKViewController類提供了一個可以平滑的動畫GLKView內(nèi)容的渲染循環(huán)。這些類擴展標準UIKit設(shè)計模式的內(nèi)容和管理視圖查看演示。結(jié)果,你可以把你的精力集中在你的OpenGL ES渲染主要 代碼和得到您的應(yīng)用程序的快速啟動和運行。的glkit框架還提供了其他功能 OpenGL ES 2和3易發(fā)展。

GLKit View 按要求繪制OpenGL ES 內(nèi)容

GLKView類提供了一個以 OpenGL ES為基礎(chǔ)的和UIView等同的繪圖循環(huán)趟大。一個UIView的實例自動配置它的圖形上下文,所有你只需要實現(xiàn)drawRect:方法 書寫Quartz 2D繪圖命令抡蛙,同樣地一個GLKView實例自動配置本身护昧,所有你的繪圖的方法只需要執(zhí)行OpenGL ES繪圖命令 。glkview類提供了這個功能,是通過保持一個framebuffer對象粗截,這個framebuffer對象保存你的OpenGL ES繪圖命令的結(jié)果惋耙,一旦你的繪圖方法結(jié)束就自動的把這些結(jié)果送到CoreAnimation

像一個標準的UIKit視圖熊昌,一個GLKitview 渲染安裝命令渲染绽榛。當您的視圖第一次顯示時,它調(diào)用您的繪圖方法-核心動畫緩存渲染輸出,當你的view顯示的時候就展示它婿屹。當你想改變你的view的內(nèi)容灭美,調(diào)用setNeedsDisplay方法和view再次調(diào)用你的繪圖方法,得到的圖像緩存昂利,并呈現(xiàn)在屏幕上届腐。當渲染圖像很少變化或僅響應(yīng)用戶操作時,這種方法非常有用蜂奸。只在需要時才呈現(xiàn)新視圖內(nèi)容犁苏,您就可以在設(shè)備上保存電池電量,并為設(shè)備執(zhí)行其他操作留出更多的時間扩所。

圖片發(fā)自簡書App

創(chuàng)建和配置一個GLkit View

您可以創(chuàng)建和配置一個glkview對象以編程方式或使用界面生成器围详。在你繪制之前,你必須把它關(guān)聯(lián)一個上下文context祖屏。

  • 當創(chuàng)建一個view時助赞,首先創(chuàng)建一個context,然后把它傳遞給視圖的initWithFrame:context:方法袁勺。
  • After loading a view from a storyboard, create a context and set it as the value of the view’s context property.

一個glkitview自動創(chuàng)建和配置自己的OpenGL ES framebuffer對象和渲染緩存renderbuffers雹食。你通過view 的drawable 屬性去控制這些對象的屬性,如清單3-1期丰。如果你改變大小群叶,規(guī)模因素漠嵌,或一個glkit觀沖性能,當下一次渲染內(nèi)容的時候它會自動刪除并重新創(chuàng)建適當?shù)膸彌_對象和渲染緩存盖呼。

- (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;
}

您可以開源glkview實例的多重采樣使用的drawablemultisample屬性。方法是一種反鋸齒化撕,鋸齒狀邊緣平滑几晤,改善圖像質(zhì)量在大多數(shù)3D應(yīng)用程序在使用更多的內(nèi)存和片段處理的時間成本如果您啟用了多采樣,總是測試您的應(yīng)用程序的性能以確保它仍然是可以接受的植阴。

繪制GLKit View

上圖概述了OpenGL ES繪圖 內(nèi)容的三個步驟:準備OpenGL ES的基礎(chǔ)設(shè)施 蟹瘾,發(fā)行的繪圖命令,并將呈現(xiàn)的內(nèi)容為核心的動畫顯示掠手。glkview類實現(xiàn)的第一個和第三個步驟憾朴。對于第二步,您將在清單3-2中實現(xiàn)示例方法的繪圖方法喷鸽。

- (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);
}

OpenGL ES glClear函數(shù)暗示众雷,任何現(xiàn)有的幀緩沖區(qū)的內(nèi)容可以被丟棄,避免昂貴的內(nèi)存操作以前的內(nèi)容加載到內(nèi)存中做祝。為了確保最佳性能砾省,您應(yīng)該在繪圖前調(diào)用此函數(shù)。

glkview類能夠提供 OpenGL ES繪制簡單的接口是因為它管理OpenGL ES渲染過程的標準部分:

  1. 在調(diào)用 繪制方法前
    1. 設(shè)置上下文
    2. 根據(jù)當前的大小混槐,繪制屬性编兄,創(chuàng)建framebuffer 和renderbuffers 對象
    3. 綁定framebuffers對象為當前的繪制命令的目標
    4. 根據(jù)framebuffer的大小設(shè)置viewport
  1. 繪制方法return后
    1. 解決多重采樣buffers
    2. 丟棄 內(nèi)容不再需要rederbuffers
    3. 把renderbuffer 內(nèi)容提交到核心動畫緩存和展示

用代理繪制

許多OpenGL app 在子類中實現(xiàn)繪制代碼。這個方式的好處是可以通過定義不同的子類實現(xiàn)多種繪制算法声登。
GLKit 適應(yīng)這種方式狠鸳。你可以把你的渲染對象設(shè)置成標準的GLKView對象的代理。與子類化GLKView和實現(xiàn)drawRect方法相反悯嗓,你的渲染類遵循GLKViewDelegate協(xié)議并實現(xiàn)
glkView:drawInRect:方法

- (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 View Controller 動畫OpenGL ES 內(nèi)容

默認的件舵,一個glkview 對象按照命令渲染內(nèi)容。就是說绅作,使用OpenGL ES 繪制的一個關(guān)鍵好處是可以使用GPU去處理復雜場景的連續(xù)的動畫芦圾,比如游戲。
對于這些情況俄认,該glkit框架提供了一個視圖控制器類个少,復雜對glkview維護一個動畫循環(huán)。這個循環(huán)遵循游戲和模擬中常見的設(shè)計模式眯杏,分為兩個階段:更新和顯示夜焦。圖3-2顯示了動畫循環(huán)的簡化示例:

圖片發(fā)自簡書App

理解這個動畫循環(huán)

在更新階段,視圖控制器調(diào)用自己的update方法(或其委托的glkviewcontrollerupdate:方法)岂贩。在這方法中茫经,您應(yīng)該準備繪制下一幀。例如,一個游戲可能會使用這種方法來確定玩家和敵人的角色的基礎(chǔ)上收到的輸入事件在上一幀的基礎(chǔ)上卸伞,和一個科學的可視化可能會使用這種方法來運行其模擬的一個步驟抹镊。如果你需要時間信息來確定下一幀你的應(yīng)用程序的狀態(tài),使用一個視圖控制器的時序特性荤傲,如timesincelastupdate屬性垮耳。

對于顯示階段,視圖控制器調(diào)用視圖的display方法遂黍,該方法反過來調(diào)用繪制方法终佛。在你的繪圖方法,你提交的OpenGL ES 繪圖命令GPU渲染你的內(nèi)容雾家。為獲得最佳性能铃彰,您的應(yīng)用程序應(yīng)該修改OpenGL ES渲染 對象在一個新的框架開始,并提交繪圖命令之后芯咧。在圖3-2中牙捉,顯示階段將著色器程序中的統(tǒng)一變量設(shè)置為在更新階段計算的矩陣,然后提交繪圖命令以呈現(xiàn)新內(nèi)容敬飒。

這個動畫循環(huán)在這兩種狀態(tài)中來回切換鹃共,根據(jù)vc的framesPerSecond屬性來設(shè)置速度。你可以通過設(shè)置preferredFramesPerSecond屬性來設(shè)置frame rate驶拱,但是vc會自動選擇一個最優(yōu)的frame rate 盡可能靠近你的選擇霜浴。

為了最好的結(jié)果: 選擇一個 你的app 能一直保持的frame rate 。一個平滑的持續(xù)的frame rate 比一個不規(guī)律的變化的frame rate 有更好的用戶體驗蓝纲。

使用GLKit 視圖 控制器

清單3-4顯示典型的策略 OpenGL ES渲染動畫的內(nèi)容進行g(shù)lkviewcontroller類和glkview實例阴孟。
清單3-4 使用glkit視圖和視圖控制器來繪制和動畫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子類)是從sb中加載税迷,有一個GLKView 實例屬性和繪制屬性永丝。viewDidLoad方法中創(chuàng)建一個OpenGL ES context 并設(shè)置view,并設(shè)置動畫循環(huán)的framerate箭养。
vc自動設(shè)置成view的delegate慕嚷,因此它實現(xiàn)了動畫循環(huán)的更新和顯示階段的方法。在update方法中毕泌,它計算顯示旋轉(zhuǎn)行星所需的變換矩陣喝检。在glkview:drawinrect:方法中,它提供了這些矩陣的著色器程序并提交繪圖命令來渲染地球幾何撼泛。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末挠说,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子愿题,更是在濱河造成了極大的恐慌损俭,老刑警劉巖蛙奖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異杆兵,居然都是意外死亡雁仲,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門琐脏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來伯顶,“玉大人,你說我怎么就攤上這事骆膝。” “怎么了灶体?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵阅签,是天一觀的道長。 經(jīng)常有香客問我蝎抽,道長政钟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任樟结,我火速辦了婚禮养交,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘瓢宦。我一直安慰自己碎连,他們只是感情好,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布驮履。 她就那樣靜靜地躺著鱼辙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪玫镐。 梳的紋絲不亂的頭發(fā)上倒戏,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機與錄音恐似,去河邊找鬼杜跷。 笑死,一個胖子當著我的面吹牛矫夷,可吹牛的內(nèi)容都是我干的葛闷。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼双藕,長吁一口氣:“原來是場噩夢啊……” “哼孵运!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蔓彩,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤治笨,失蹤者是張志新(化名)和其女友劉穎驳概,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體旷赖,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡顺又,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了等孵。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片稚照。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖俯萌,靈堂內(nèi)的尸體忽然破棺而出果录,到底是詐尸還是另有隱情,我是刑警寧澤咐熙,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布弱恒,位于F島的核電站,受9級特大地震影響棋恼,放射性物質(zhì)發(fā)生泄漏返弹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一爪飘、第九天 我趴在偏房一處隱蔽的房頂上張望义起。 院中可真熱鬧,春花似錦师崎、人聲如沸默终。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽穷蛹。三九已至,卻和暖如春昼汗,著一層夾襖步出監(jiān)牢的瞬間肴熏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工顷窒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蛙吏,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓鞋吉,卻偏偏與公主長得像鸦做,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子谓着,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354

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