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的博客

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