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視圖熊昌,一個GLKit
view 渲染安裝命令渲染绽榛。當您的視圖第一次顯示時,它調(diào)用您的繪圖方法-核心動畫緩存渲染輸出,當你的view顯示的時候就展示它婿屹。當你想改變你的view的內(nèi)容灭美,調(diào)用setNeedsDisplay
方法和view再次調(diào)用你的繪圖方法,得到的圖像緩存昂利,并呈現(xiàn)在屏幕上届腐。當渲染圖像很少變化或僅響應(yīng)用戶操作時,這種方法非常有用蜂奸。只在需要時才呈現(xiàn)新視圖內(nèi)容犁苏,您就可以在設(shè)備上保存電池電量,并為設(shè)備執(zhí)行其他操作留出更多的時間扩所。
創(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渲染過程的標準部分:
- 在調(diào)用 繪制方法前
- 設(shè)置上下文
- 根據(jù)當前的大小混槐,繪制屬性编兄,創(chuàng)建framebuffer 和renderbuffers 對象
- 綁定framebuffers對象為當前的繪制命令的目標
- 根據(jù)framebuffer的大小設(shè)置viewport
- 繪制方法return后
- 解決多重采樣buffers
- 丟棄 內(nèi)容不再需要rederbuffers
- 把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)的簡化示例:
理解這個動畫循環(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:
方法中,它提供了這些矩陣的著色器程序并提交繪圖命令來渲染地球幾何撼泛。