OpenGL ES之绘制三角形(一)
2017-07-03 本文已影响266人
冰三尺
这里是OpenGL ES第一次上手, 文章的目的是实现绘制一个三角形
GLKView是一个使用OpenGL ES进行绘图的默认实现, GLKView简化了绘图的配置
实现一个绘图需要7个步骤
- 为缓存生成一个独
- 为接下来的运算绑
- 复制数组到缓存
- 启动
- 设置指针
- 绘图
7)释放资源
//本例中使用的事从storyboard中加载, 所以需要把Main.storyboard的类关联到GLKViewController
@interface ViewController : GLKViewController
{
GLuint vertexBufferID; //顶点数据缓存的标识符
}
//GLKBaseEffect是GLKit提供的一个内建类, GLKBaseEffect的存在是为了简化很多OpenGL ES 的常用操作, GLKBaseEffect隐藏了多个iOS版本对OpenGL ES支持的差异,
@property (strong, nonatomic) GLKBaseEffect *baseEffect;
@end
//定义一个C语言的结构体SceneVertex, 用于保存GLKVector3数据, 顶点的坐标可以用一个起始于远点的矢量来表示
typedef struct {
GLKVector3 positionCoords;
}SceneVertex;
//vertices变量是一个用顶点数据初始化的C语言的数组, 这个变量用于定义一个三角形
static const SceneVertex vertices[] =
{
{{-0.5f, -0.5f, 0.0}},
{{ 0.5f, -0.5f, 0.0}},
{{-0.5f, 0.5f, 0.0}}
};
OpenGL ES的坐标和UIView的坐标是不一样的, 下图展示的及时上面定义的三角形的坐标
屏幕快照 2017-07-03 下午1.59.36.png设置OpenGL ES上线下文
- (void)setEGALContext {
//创建一个GLKView
GLKView *view = (GLKView *)self.view;
NSAssert([view isKindOfClass:[GLKView class]],
@"View controller's view is not a GLKView");
//初始化EAGLContext上线文, 给GLKView绑定EAGL
/**
* kEAGLRenderingAPIOpenGLES2代表的事OpenGL ES 2.0
*/
view.context = [[EAGLContext alloc]
initWithAPI:kEAGLRenderingAPIOpenGLES2];
//给当前的OpenGL ES设置将会用到的上下文
[EAGLContext setCurrentContext:view.context];
}
GLKBaseEffect提供了不依赖于所使用的OpenGL ES版本的控制OpenGL ES 渲染的方法
如果没有GLKBaseEffect和GLKit类, 完成这个简单的例子需要在OpenGL ES 2.0 的Shading Language编写一个小的GPU程序, GLKBaseEffect会在需要的时候自动创建GPU程序
- (void)setBaseEffect {
self.baseEffect = [[GLKBaseEffect alloc] init];
self.baseEffect.useConstantColor = GL_TRUE;
//控制渲染颜色的方式有很多种, 下面是一个恒定的白色三角形, 使用一个保存颜色四个元素的结构体来设置恒定的颜色
//颜色格式为RGBA
GLKVector4 vector4 = GLKVector4Make(
1.0f,
1.0f,
1.0f,
1.0f);
self.baseEffect.constantColor = vector4;
}
创建并使用一个用于保存顶点数据的顶点属性数组缓存, 主要用于CPU控制的内存与GPU控制的内存之间的数据交换的唯一标识符
1) 为缓存生成一个独一无二的标识符
2) 为接下来的运算绑定缓存
3) 复制数组到缓存
- (void)setBufferData {
//glGenBuffers用于生成一个独一无二的标识符, 第一个参数指定要生成的缓存的数量为1, 第二个参数指向生成标识符的内存地址, 并保存. 当前情况下, 一个标识符被生成并保存在vertexBufferID实例变量中
glGenBuffers(1, // STEP 1
&vertexBufferID);
//glBindBuffer函数用于绑定指定标识符的缓存到当前的缓存, OpenGL ES 保存不同类型的缓存到当前上下文的不同部位, 但是在同一时刻只能绑定一个缓存
//第一个参数是一个常亮, 用于指定缓存的类型, GL_ARRAY_BUFFER类型用于指定一个顶点属性数组, 三角形就是属于这种类型, 第二个参数是要绑定的标识符
glBindBuffer(GL_ARRAY_BUFFER, // STEP 2
vertexBufferID);
//glBufferData函数复制应用的顶点数据到当前上下文绑定顶点的缓存中
glBufferData( // STEP 3
GL_ARRAY_BUFFER, // 指定当前上下文所绑定的是哪一个缓存
sizeof(vertices), // 复制到这个缓存的字节数
vertices, // 要复制的字节的地址
GL_STATIC_DRAW); // 提示缓存在未来会被怎样的使用, GL_STATIC_DRAW会提示上下文缓存中的内容适合复制到GPU控制的内存, 对其很少修改, 这个信息会提示OpenGL ES来优化内存使用
}
- (void)viewDidLoad {
[super viewDidLoad];
[self setEGALContext];
[self setBaseEffect];
//glClearColor函数用于设置当前上下文的清除颜色, 由RGBA组成, 用于在上下文的帧缓存被清除时初始化每个像素的颜色值
glClearColor(0.5f, 0.5f, 0.5f, 1.0f); // background color
[self setBufferData];
}
所有的配置结束之后, 下面开始执行绘图
GLKViewControllerDelegate的代理在配置工作完成之后会自动执行绘图
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
//该方法是GLKView的委托方法, 实现该方法就意味着要告诉GLKBaseEffect去准备号OpenGL ES上下文
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
[self.baseEffect prepareToDraw];
//清除之前设置的值, 使用glClearColor设置的值
//注意: 该glClear功能提示OpenGL ES可以丢弃任何现有的帧缓冲区内容,避免了将先前内容加载到内存中的昂贵的内存操作。为确保最佳性能,您应该在绘制之前始终调用此函数。
glClear(GL_COLOR_BUFFER_BIT);
/**
* 4) 启动
* 5) 设置指针
* 6) 绘图
*/
//该方法用于启动顶点缓存的渲染操作,
glEnableVertexAttribArray( // STEP 4
GLKVertexAttribPosition);
//该方法会告诉OpenGL ES 顶点数据在哪里. 以及怎么解释顶点数据,
glVertexAttribPointer( // STEP 5
GLKVertexAttribPosition, //当前绑定的缓存包含每个顶点的位置信息
3, // 每个顶点位置有几个部分
GL_FLOAT, // 告诉OpenGL ES 每个顶点位置都为一个浮点类型的值
GL_FALSE, // 告诉OpenGL ES 小数点固定数据是否可以被改变
sizeof(SceneVertex), // 每个顶点的保存需要多少个字节
NULL); // NULL 告诉 OpenGL ES 可以从当前绑定的顶点缓存的开始位置访问顶点数据
//执行绘图
// STEP 6
glDrawArrays(GL_TRIANGLES, //告诉GPU 如何去处理绑定在顶点缓存内的顶点数据, 该参数是渲染一个三角形
0, // 要渲染的第一个顶点的位置
3); // 要渲染的顶点的数量
}
在我们不需要执行程序时, 别忘记释放资源
- (void)dealloc {
//获取当前的GLKView
GLKView *view = (GLKView *)self.view;
[EAGLContext setCurrentContext:view.context];
/**
* 7)释放资源
*/
//删除不在需要的顶点缓存和上下文
if (0 != vertexBufferID)
{
glDeleteBuffers (1, // STEP 7
&vertexBufferID);
vertexBufferID = 0; //设置为0避免在对应的缓存被删除之后存在未被使用的无效标识符
}
((GLKView *)self.view).context = nil; //设置视图的上下文属性为nil
[EAGLContext setCurrentContext:nil]; //设置当前上下文的属性为nil
}
运行之后的效果
Simulator Screen Shot 2017年7月3日 下午3.22.52.png