OpenGL在IOS中的應用

IOS的OpenGL應用

一、搭建開發環境
1. 打開Xcode, 新建一個工程
選擇:IOS -> Application -> Single View Application模板

 
輸入工程名稱和基本信息,勾選“UseStoryboards”,然後創建
IOS的OpenGL應用 - 過☆客 - 過☆客
 
2. 添加必要的框架
在“Build Phases”中,添加三個框架
QuartzCore.framework
OpenGLES.framework
GLKit.framework

3. 修改viewController。h
添加 “#import<GLKit/glkit.h>”,並將它修改爲繼承"GLKViewController"


4. 修改“view”的類
雙擊“MainStoryboard.storyboard”展開,選擇"view"
IOS的OpenGL應用 - 過☆客 - 過☆客
然後,在“Identity Inspector"中,將它的類改爲”GLKView“
IOS的OpenGL應用 - 過☆客 - 過☆客
好了,OpenGL的環境基本上搭建出來了。

二、增加自己代碼
基本上,所有的代碼都是加到ViewController.m文件中
1、添加全局屬性聲明

@interface ViewController ()

@property(strong,nonatomic)EAGLContext* context;

@property(strong,nonatomic)GLKBaseEffect* effect;

@end

@implementation ViewController

@synthesize context, effect;

2、 添加一組頂點數據
這是一個正方形頂點數組。實際上它是二個三角形接合而成的

GLfloat squareVertexData[48] =

{

    0.5f,   0.5f,  -0.9f,  0.0f,   0.0f,   1.0f,   1.0f,   1.0f,

    -0.5f,   0.5f,  -0.9f,  0.0f,   0.0f,   1.0f,   1.0f,   1.0f,

    0.5f,  -0.5f,  -0.9f,  0.0f,   0.0f,   1.0f,   1.0f,   1.0f,

    0.5f,  -0.5f,  -0.9f,  0.0f,   0.0f,   1.0f,   1.0f,   1.0f,

    -0.5f,   0.5f,  -0.9f,  0.0f,   0.0f,   1.0f,   1.0f,   1.0f,

    -0.5f,  -0.5f,  -0.9f,  0.0f,   0.0f,   1.0f,   1.0f,   1.0f,

};

每行頂點數據的排列含義是:

頂點X、頂點Y,頂點Z、法線X、法線Y、法線Z、紋理S、紋理T。

在後面解析此數組時,將參考此規則。

頂點位置用於確定在什麼地方顯示,法線用於光照模型計算,紋理則用在貼圖中。

一般約定爲“頂點以逆時針次序出現在屏幕上的面”爲“正面”。

世界座標是OpenGL中用來描述場景的座標,Z+軸垂直屏幕向外,X+從左到右,Y+軸從下到上,是右手笛卡爾座標系統。我們用這個座標系來描述物體及光源的位置。


三、初始化OpenGL環境

1、 基本的初始化代碼

在ViewController.m中有個函數(void)viewDidLoad,它是程序運行時,初始化回調函數。在viewDidLoad函數內補充我們自己的初始化代碼。

// 使用“ES2”創建一個“EAGLEContext”實例

    self.context = [[[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2]autorelease];

    // 將“view”的context設置爲這個“EAGLContext”實例的引用。並且設置顏色格式和深度格式。

    GLKView* view = (GLKView*)self.view;

    view.context = self.context;

    view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;

    view.drawableDepthFormat = GLKViewDrawableDepthFormat24;

    // 將此“EAGLContext”實例設置爲OpenGL的“當前激活”的“Context”。這樣,以後所有“GL”的指令均作用在這個“Context”上。隨後,發送第一個“GL”指令:激活“深度檢測”。

    [EAGLContext setCurrentContext:context];

    glEnable(GL_DEPTH_TEST);

    // 創建一個GLK內置的“着色效果”,並給它提供一個光源,光的顏色爲綠色。

    self.effect = [[[GLKBaseEffect alloc]init]autorelease];

    self.effect.light0.enabled = GL_TRUE;

    self.effect.light0.diffuseColor = GLKVector4Make(0.0f, 1.0f, 0.0f, 1.0f);

2、 運行。現在應該是粉紅色屏幕了(目前場景仍是空的),說明初始化過程沒問題


四、 將項點數據寫入能用的頂點屬性存儲區

1、 寫入過程

首先將數據保存進GUP的一個緩衝區中,然後再按一定規則,將數據取出,複製到各個通用頂點屬性中。

注:如果頂點數據只有一種類型(如單純的位置座標),換言之,在讀數據時,不需要確定第一個數據的內存位置(總是從0開始),則不必事先保存進緩衝區。

2、 頂點數組保存進緩衝區

// 聲明一個緩衝區的標識(GLuint類型)讓OpenGL自動分配一個緩衝區並且返回這個標識的值.綁定這個緩衝區到當前“Context”.最後,將我們前面預先定義的頂點數據“squareVertexData”複製進這個緩衝區中。

    // 注:參數“GL_STATIC_DRAW”,它表示此緩衝區內容只能被修改一次,但可以無限次讀取。

    GLuint buffer;

    glGenBuffers(1, &buffer);

    glBindBuffer(GL_ARRAY_BUFFER, buffer);

    glBufferData(GL_ARRAY_BUFFER, sizeof(squareVertexData), squareVertexData, GL_STATIC_DRAW);

3、將緩衝區的數據複製進能用頂點屬性中

glEnableVertexAttribArray(GLKVertexAttribPosition);

    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 4*8, (char*)NULL + 0);

    首先,激活頂點屬性(默認它的關閉的)。“GLKVertexAttribPosition”是頂點屬性集中“位置Position”屬性的索引。

    頂點屬性集中包含五種屬性:位置、法線、顏色、紋理0,紋理1。

    它們的索引值是0到4。

    激活後,接下來使用“glVertexAttribPointer”方法填充數據。

    參數含義分別爲:

    頂點屬性索引(這裏是位置)、3個分量的矢量、類型是浮點(GL_FLOAT)、填充時不需要單位化(GL_FALSE)、在數據數組中每行的跨度是32個字節(4*8=32。從預定義的數組中可看出,每行有8個GL_FLOAT浮點值,而GL_FLOAT佔4個字節,因此每一行的跨度是4*8)。

    最後一個參數是一個偏移量的指針,用來確定“第一個數據”將從內存數據塊的什麼地方開始。

4、繼續複製其他數據
在前面定義了項點數據數組中,還包含了法線和紋理座標,所以參照上面的方法,將剩餘的數據分別複製進能用頂點屬性

glEnableVertexAttribArray(GLKVertexAttribNormal);

    glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FLOAT, 4*8, (char*)NULL + 12 );

    glEnableVertexAttribArray(GLKVertexAttribTexCoord0);

    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 4*8, (char*)NULL+24);

原則上,必須先“激活”某個索引,才能將數據複製進這個索引表示的內存中。

因爲紋理座標只有兩個(S和T),所以上面參數是“2”。


 五、執行渲染循環

萬事具備,現在可以讓OpenGL顯示一些東西了。

在GLKit框架中,儘管OpenGL的行爲,是由“GLKViewController”和“GLKView”聯合控制的,但實際上“GLKView”類中完全不需要寫任何自己的代碼,因爲,“GLKView”類中每幀觸發的兩個方法“update”和“glkView”,都轉交給“GLKViewController”代理執行了。

1、添加代理方法

在ViewController.m中添加兩個方法

- (void)update

{

}

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect

{

}

這兩個方法每幀都執行一次(循環執行),一般執行頻率與屏幕刷新率相同(但也可以更改)。

第一次循環時,先調用“glkView”再調用“update”。

一般,將場景數據變化放在“update”中,而渲染代碼則放在“glkView”中。

2、渲染場景

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect

{

    glClearColor(0.3f, 0.6f, 1.0f, 1.0f);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    [self.effect prepareToDraw];

    glDrawArrays(GL_TRIANGLES, 0, 6);

}

前兩行爲渲染前的“清除”操作,清除顏色緩衝區和深度緩衝區中的內容,並且填充淡藍色背景(默認背景是黑色)。

“prepareToDraw”方法,是讓“效果Effect”針對當前“Context”的狀態進行一些配置,它始終把“GL_TEXTURE_PROGRAM”狀態定位到“Effect”對象的着色器上。此外,如果Effect使用了紋理,它也會修改“GL_TEXTURE_BINDING_2D”。

接下來,用“glDrawArrays”指令,讓OpenGL“畫出”兩個三角形(拼合爲一個正方形)。OpenGL會自動從通用頂點屬性中取出這些數據、組裝、再用“Effect”內置的着色器渲染。

3、運行結果


IOS的OpenGL應用 - 過☆客 - 過☆客

渲染內容終於呈現了,藍色背景、還有一個綠色矩形(其實是兩個三角形)。綠色並非是此物體的本色,而受是綠色燈光影響。


ps:第一次在xcode中寫gl程序,完全借鑑mississi的博客

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章