update: 2012/06/23
reference:
1. Beginning OpenGL ES 2.0 with GLKit Part 1 | Ray Wenderlich
GLKView
A. 說明:
1. GLKit 是 iOS 5 的新 API, 它可以讓用 OpenGL ES 來開發 App 較以往更為容易.
2. GLKit 包含四個主要的部分:
a. GLKView/GLKViewController
這些類別將以往在 OpenGL ES 中, 所使用的一成不變的程式碼作大量的
抽象化處理, 以方便來設置基本的 OpenGL ES 專案.
b. GLKEffects
這些類別實作了使用在 OpenGL ES 1.0 中普遍的著色行為(shading behaviors),
使得轉變到 OpenGL ES 2.0 更加容易. 它們也是使用手工的方式來處理一些
基本的光源與貼圖的工作.
c. GLMath
在 iOS 5 的遊戲中, 相當重要的是每個遊戲都需要有各自的數學函式庫,
而這些數學函式庫都包含共同常規的向量與矩陣運算. 現在使用 GLMath,
將提供大部份共同常規的數學函式.
d. GLKTextureLoader
這個類別使得在 OpenGL ES 中, 載入圖片作為紋理貼圖更加容易. 較以往
必須寫一個複雜的方法來處理不同圖片的檔案格式; 現在, 只要呼叫單一的
方法, 就可以載入紋理了.
--------------------------------------------------------------------------------
B. 新增專案
1. Xcode > File > New > Project... > iOS > Application >
Empty Application > Next
Product Name: HelloGLKit
Company Identifier: com.blogspotDevice Family: iPhone
Use Automatic Reference Counting: checked
> Next > Create
2. 編譯並執行:
得到全白的畫面
C. GLKView 介紹
1. 說明:
a. 要開始使用 OpenGL ES 2.0 的第一件事, 是幫 window (UIWindow) 新增
一個 subview, 使它可以利用 OpenGL 來繪製物體. 如果你之前有用一般的
方式來寫過 OpenGL ES 2.0 的程式, 就會知道需要使用大量一成不變(刻版)
的程式碼來完成, 例如: 建立 render buffer 與 frame buffer 等等.
b. 現在, 可以輕易的使用 GLKit 的新類別: GLKView 來完成. 無論何時, 當你
想要在一個 view 裡使用 OpenGL 來繪製, 你只需簡單地新增一個 GLKView
(它是 UIView 的一個標準子類別) 並且設定好一些屬性即可.
c. 接著, 你可以設定一個類別作為 GLKView 的委派(delegate), 當需要被繪製時,
該類別的某個方法就會被呼叫. (你可以在這個方法中, 放入你的 OpenGL
繪圖指令)
**********************************************
2. 新增 Framework:
QuartzCore
- Add 2D graphics rendering support.
- Add 2D graphics rendering support.
OpenGLES
- Is used for visualizing 2D and 3D data.
GLKit
- Provides libraries of commonly needed functions and classes to reduce the effort
needed to create a new OpenGL ES 2.0 application or the effort required to port
an existing OpenGL ES 1.1 application to OpenGL ES 2.0.
**********************************************
3. 開啟 AppDelegate.h 檔案, 修改如下:
#import <UIKit/UIKit.h>
//@add
#import <GLKit/GLKit.h>
//@interface AppDelegate : UIResponder <UIApplicationDelegate>
//@update for set as GLKView's delegate
@interface AppDelegate : UIResponder <UIApplicationDelegate, GLKViewDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
**********************************************
4. 開啟 AppDelegate.m 檔案, 修改如下:
....
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
//@add for GLKView
//
// step 1: Create a OpenGL context
//
// 1-1: An EAGLContext manages all of the information iOS needs to draw
// with OpenGL.
// 1-2: And specify what version of the API you want to use.(Here, OpenGL ES 2.0)
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
// step 2: Create a GLKView
//
// This creates a new instance of a GLKView, and makes it as large as the
// entire window.
GLKView *view = [[GLKView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// step 3: Set the GLKView's context
//
// Tell GLKView to use the OpenGL context.
view.context = context;
// step 4: Set the GLKView's delegate
//
// 4-1: This sets the current class (AppDelegate) as the GLKView's delegate.
// 4-2: This means whenever the view needs to be redrawn, it will call
// a method named glkView:drawInRect on whatever class you specify here.
// We will implement this inside the App Delegate shortly to contain
// some basic OpenGL commands to paint the screen red.
view.delegate = self;
// step 5: Add the GLKView as a subview
[self.window addSubview:view];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
....
#pragma mark - GLKViewDelegate
//@add: for implement delegate method
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
// specify the RGB and alpha (transparency) values to use when clearing the screen.
glClearColor(1.0, 0.0, 0.0, 1.0);
// actually perform the clearing.
glClear(GL_COLOR_BUFFER_BIT);
}
@end
**********************************************
5. 編譯並執行:
對於完全是 OpenGL 新手的人來說, 可能無法感受到;
對於以前曾用一般 OpenGL 的方式做過的人而言, 的確是方便許多了.
--------------------------------------------------------------------------------
D. 選擇性的參考資料: GLKView 的其它屬性與方法
1. 說明:
目前我們只設定了 GLKView 的一些屬性(context 與 delegate), 在此順便
介紹 GLKView 的其它屬性與方法, 將來可能會用到.
2. drawableColorFormat (屬性)
a. OpenGL context 有一個用來儲存顯示在螢幕上的顏色之 buffer. 你可以
使用這個屬性來設定在 buffer 中, 每個像素的顏色格式.
b. 這個屬性的預設值是: GLKViewDrawableColorFormatRGBA8888,
代表著: 在 buffer 中, 針對 RGBA 各自都使用了 8 bits(因此每個像素
使用了 4 bytes), 這樣的好處是: 使用了最寬廣的顏色範圍, 可以讓 App
看起來較美觀.
c. 但是, 如果你的 App 可以僅使用較低範圍的顏色, 你可能想要將此屬性
的值設為: GLKViewDrawableColorFormatRGB565, 這會讓你的 App
花費較少的資源(記憶體與處理時間).
3. drawableDepthFormat (屬性)
a. OpenGL context 也可以選擇性地連結另一個 buffer: depth buffer. 它可以
幫助確認當物體較靠近觀察者前方(相對於較遠的)時, 才顯示其像素.
b. 這個方式預設為: OpenGL 將最靠近觀察者的物件之每個像素儲存到 buffer 裡.
當要開始繪製出像素時, 它會檢查 depth buffer 看看是否已經有畫出較接近
觀察者的像素, 如果有的話便將目前的像素摒棄掉, 否則就將此像素加入到
depth buffer 與 color buffer 裡.
c. 你可以設定這個屬性來選擇 depth buffer 的形式, 預設值為:
GLKViewDrawableDepthFormatNone, 代表沒有啟用 depth buffer 功能.
d. 但是如果你想要啓用此功能(通常使用在 3D 遊戲中), 你應當選擇:
GLKViewDrawableDepthFormat16 或 GLKViewDrawableDepthFormat24.
二者差別在於: 設為 GLKViewDrawableDepthFormat16 時, 你的 App 會使用
較少的資源, 但是當二個物體非常靠近時, 就可能會發生渲染的問題.
4. drawableStencilFormat (屬性)
a. OpenGL context 可以連結的另一個選擇性 buffer 為: stencil buffer.
模板緩衝可以協助你限制只在螢幕的特定部分作繪製的工作.
通常它對於處理某些東西特別有用, 例如: 陰影. 你可以使用 stencil buffer
來確保陰影投射(cast)到地板上.
b. 這個屬性的預設值為: GLKViewDrawableStencilFormatNone, 代表:
沒有使用 stencil buffer, 但是你可以啟用它, 設定為唯一可選的值:
GLKViewDrawableStencilFormat8.
5. drawableMultisample (屬性)
a. 最後一個可經由 GLKView 屬性設定的選擇性 buffer 為: multisampling buffer.
如果你曾經用 OpenGL 來畫線, 並且注意到 "鋸齒狀線條" 情形, 多重採樣緩衝
可以協助處理這個問題(抗鋸齒化).
b. 基本上它所處理的是: 取代對每個像素呼叫一次 fragment shader 的作法.
而將像素劃分為更小的單位, 並且在較小層級的細節處理上多次呼叫
fragment shader. 其結果通常會使幾何物體的邊緣顯得更加光滑.
c. 但是, 小心設置這個屬性, 因為它需要花費更多的處理時間與記憶體.
預設值為: GLKViewDrawableMultisampleNone, 但是你可以啟用它,
設定為唯一可選的值: GLKViewDrawableMultisample4X.
6. drawableHeight/drawableWidth (屬性)
這些是唯讀的屬性, 用來指出 buffers 的高與寬. 以 view 的 bounds 與
contentSize 為基準, 當 bounds 與 contentSize 改變時, buffers 就會自動調整大小.
7. snapshot (方法)
這是用手動的方式, 從目前 view 的 context 中, 取得一個 UIImage.
8. bindDrawable (方法)
a. OpenGL 還有另外一個 buffer: frame buffer, 基本上 frame buffer 是其它
我們討論過的 buffers (color buffer, depth buffer, stencil buffer 等等) 之集合.
b. 在呼叫 glkView:drawInRect 方法之前, GLKit 會在場景的背後將設定的屬性
綁定到 frame buffer 裡. 但是, 如果你的遊戲 App 需要變更不同的 frame buffer
來執行一些其它種類的渲染(例如, 你要使用不同的紋理貼圖), 你可以使用
bindDrawable 方法來告訴 GLKit 去重新綁定到你設定的 frame buffer.
9. deleteDrawable (方法)
a. GLKView 與 OpenGL 在處理 buffers 時, 會使用到大量的實體記憶體. 假如
你的 GLKView 無法顯示出來, 你可能會發現先暫時地取消配置記憶體, 直到
內容再次可被顯示出來, 是有效的方式. 如果你想要這麼做, 只需要使用
deleteDrawable 方法即可.
b. 下一次, 當 view 要被繪製出來時, GLKView 會在場景的背後自動重新配置
記憶體, 相當方便不是嗎?
10. enableSetNeedsDisplay (屬性) and display (方法)
a. 預設情況下, GLKView 只會在有需要時才會自行更新, 亦即: 當 views
第一次被繪製出來, 長寬大小改變, 等等. 然而, 對於遊戲 App 而言,
你經常需要去重新繪製每個 frame!
b. 我們可以藉由將 enableSetNeedsDisplay 設為 false 來停用 GLKView 的
這個預設行為. 然後, 當我們要更新螢幕內容時, 可藉由在 GLKView 上
呼叫 display 方法, 來控制重新繪製的時機.
--------------------------------------------------------------------------------
E. 更新 GLKView
1. 開啓 AppDelegate.h 檔案, 修改如下:
#import <UIKit/UIKit.h>
//@add
#import <GLKit/GLKit.h>
#import <QuartzCore/QuartzCore.h> // used for CADisplayLink
//@interface AppDelegate : UIResponder <UIApplicationDelegate>
//@update for set as GLKView's delegate
@interface AppDelegate : UIResponder <UIApplicationDelegate, GLKViewDelegate>
{
//@add
float _curRed;
BOOL _increasing;
}
@property (strong, nonatomic) UIWindow *window;
//@add
- (void)render:(CADisplayLink *)displayLink;
@end
********************************************
2. 開啓 AppDelegate.m 檔案, 修改如下:
....
// step 01
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//@add
_increasing = YES;
_curRed = 0.0;
....
}
....
// step 02
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
//@add
if (_increasing) {
_curRed += 0.01;
} else {
_curRed -= 0.01;
}
if (_curRed >= 1.0) {
_curRed = 1.0;
_increasing = NO;
}
if (_curRed <= 0.0) {
_curRed = 0.0;
_increasing = YES;
}
// specify the RGB and alpha (transparency) values to use when clearing the screen.
//glClearColor(1.0, 0.0, 0.0, 1.0);
//@update
glClearColor(_curRed, 0.0, 0.0, 1.0);
// actually perform the clearing.
glClear(GL_COLOR_BUFFER_BIT);
}
....
// step03
//@add: for synchronize the time we render with OpenGL
// to the rate at which the screen refreshes.
- (void)render:(CADisplayLink *)displayLink
{
GLKView *view = [self.window.subviews objectAtIndex:0];
[view display];
}
....
// step04
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
....
view.delegate = self;
//@add: for synchronize
view.enableSetNeedsDisplay = NO;
CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(render:)];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
// step 5: Add the GLKView as a subview
[self.window addSubview:view];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
....
********************************************
3. 編譯並執行
你會看到脈動式的 "緊急警報" 效果 (黑 -> 漸紅 -> 紅)
沒有留言:
張貼留言
注意:只有此網誌的成員可以留言。