用OpenGL ES and GLKit繪制 譯文

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

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

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

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

圖片發(fā)自簡書App

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

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

  • 當(dāng)創(chuàng)建一個(gè)view時(shí),首先創(chuàng)建一個(gè)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.

一個(gè)glkitview自動創(chuàng)建和配置自己的OpenGL ES framebuffer對象和渲染緩存renderbuffers。你通過view 的drawable 屬性去控制這些對象的屬性,如清單3-1。如果你改變大小,規(guī)模因素,或一個(gè)glkit觀沖性能,當(dāng)下一次渲染內(nèi)容的時(shí)候它會自動刪除并重新創(chuàng)建適當(dā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實(shí)例的多重采樣使用的drawablemultisample屬性。方法是一種反鋸齒,鋸齒狀邊緣平滑,改善圖像質(zhì)量在大多數(shù)3D應(yīng)用程序在使用更多的內(nèi)存和片段處理的時(shí)間成本如果您啟用了多采樣,總是測試您的應(yīng)用程序的性能以確保它仍然是可以接受的。

繪制GLKit View

上圖概述了OpenGL ES繪圖 內(nèi)容的三個(gè)步驟:準(zhǔn)備OpenGL ES的基礎(chǔ)設(shè)施 ,發(fā)行的繪圖命令,并將呈現(xiàn)的內(nèi)容為核心的動畫顯示。glkview類實(shí)現(xiàn)的第一個(gè)和第三個(gè)步驟。對于第二步,您將在清單3-2中實(shí)現(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繪制簡單的接口是因?yàn)樗芾鞳penGL ES渲染過程的標(biāo)準(zhǔn)部分:

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

用代理繪制

許多OpenGL app 在子類中實(shí)現(xiàn)繪制代碼。這個(gè)方式的好處是可以通過定義不同的子類實(shí)現(xiàn)多種繪制算法。
GLKit 適應(yīng)這種方式。你可以把你的渲染對象設(shè)置成標(biāo)準(zhǔn)的GLKView對象的代理。與子類化GLKView和實(shí)現(xiàn)drawRect方法相反,你的渲染類遵循GLKViewDelegate協(xié)議并實(shí)現(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;
}

一個(gè)GLKit View Controller 動畫OpenGL ES 內(nèi)容

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

圖片發(fā)自簡書App

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

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

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

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

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

使用GLKit 視圖 控制器

清單3-4顯示典型的策略 OpenGL ES渲染動畫的內(nèi)容進(jìn)行g(shù)lkviewcontroller類和glkview實(shí)例。
清單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

在這個(gè)例子中,planetviewcontroller類的一個(gè)實(shí)例(一個(gè)自定義glkviewcontroller子類)是從sb中加載,有一個(gè)GLKView 實(shí)例屬性和繪制屬性。viewDidLoad方法中創(chuàng)建一個(gè)OpenGL ES context 并設(shè)置view,并設(shè)置動畫循環(huán)的framerate。
vc自動設(shè)置成view的delegate,因此它實(shí)現(xiàn)了動畫循環(huán)的更新和顯示階段的方法。在update方法中,它計(jì)算顯示旋轉(zhuǎn)行星所需的變換矩陣。在glkview:drawinrect:方法中,它提供了這些矩陣的著色器程序并提交繪圖命令來渲染地球幾何。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容