OpenGL ES 主要讲解怎么让程序在渲染的每一步中尽可能利用好OpenGL ES和图形硬件
第一步:为GPU提供要处理的3D数据
程序从CPU的内存复制数据到OpenGL ES的缓存(在GPU取得一个缓存的所有权以后,运行在CPU中的程序理想情况下将不再接触这个缓存)这意味着GPU使用缓存中的数据工作的同事,运行在CPU中的程序可以继续执行
一:为缓存提供数据的7个步骤
(1)生成(Generate):请求OpenGL ES 为图形处理器控制的缓存生成一个独一无二的标识符 (c函数:glGenBuffers())
(2)绑定(Bind):告诉OpenGL ES为接下来的运算使用一个缓存(c函数:glBindBuffer())
(3)缓存数据(Buffer Data):让OpenGL ES为当前绑定的缓存分配并初始化足够的连续内存(通常是从CPU控制的内存复制数据到分配的内存)(c函数:glBufferData()或glBufferSubData())
(4)启用(Enable)或 禁止(Disable):告诉OpenGL ES在接下来的渲染中是否使用缓存中的数据(c函数:glEnableVertexAttribArray()或glDisableVertexAttribArray())
(5)设置指针(Set Pointers):告诉OpenGL ES 在缓存中数据的类型和所需要访问的数据的内存偏移(c函数:glVertexAttribPointer())
(6)绘图(Draw):告诉OpenGL ES使用当前绑定并启用在缓存中的数据渲染整个场景或者某个场景的一部分(c函数:glDrawArrays()或glDrawElements())
(7)删除(Delete):告诉OpenGL ES删除以前生成的缓存并释放相关资源(c函数:glDeleteBuffers())
二:OpenGL ES 的上下文
用于配置OpenGL ES的保存在特定平台的软件数据结构中的信息会被封装到一个OpenGL ES上下文中,包括
(1)跟踪用于渲染的帧缓存
(2)跟踪用于几何数据、颜色等的缓存
(3)决定是否使用某些功能,比如:纹理,灯光
(4)渲染定义当前的坐标系统
绘制一个白色三角形代码
ViewController.h
#import <GLKit/GLKit.h>
@interface ViewController : GLKViewController
@end
ViewController.m
#import "ViewController.h"
//定义一个结构体,用来保存一个GLKVector3类型的成员 positionCoords
typedef struct {
//GLKVector3类型保存3个坐标,x,y,z
GLKVector3 positionCoords;
}SceneVertex;
//定义要在示例中使用的三角形的顶点数据
static const SceneVertex vertices[] = {
{{-0.5f,-0.5f,0.0}}, //lower left corner
{{0.5f,-0.5f,0.0}}, //lower right corner
{{-0.5f,0.5f,0.0}} //upper left corner
};
@interface ViewController ()
{
//用于盛放用到的顶点数据的缓存的OpenGL ES的标识符
GLuint vertexBufferId;
}
@property (strong, nonatomic)GLKBaseEffect * baseEffect;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
GLKView *view = (GLKView *)self.view;
//创建一个OpenGL ES 2.0上下文,并将其提供给视图
view.context = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
//Make the new context current,在任何其他的OpenGL ES配置或者渲染发生之前,应用的GLKView实例的上下文属性都需要设置为当前
//setCurrentContext方法为接下来的OpenGL ES运算设置将会用到的上下文
[EAGLContext setCurrentContext:view.context];
//初始化baseEffect,提供标准的openGL ES 2.0着色语言程序,并设置常量用于所有后续渲染
self.baseEffect = [[GLKBaseEffect alloc]init];
self.baseEffect.useConstantColor = GL_TRUE;
//设置constantColor (red,green,blue,alpha)
self.baseEffect.constantColor = GLKVector4Make(1.0f, 1.0f, 1.0f, 1.0f);
//background color
//glClearColor()函数设置当前openGL ES的上线文的“清除颜色”
glClearColor(122/255.0, 155/255.0, 209/255.0, 1.0);
/*
创建并使用一个用于保存顶点数据的顶点属性数组缓存
*/
/*
第一步
为缓存生成一个独一无二的标识符,
第一个参数用于指定要生成的缓存标识符的数量
第二个参数是一个指针,指向生成的标识符的内存保存位置
*/
glGenBuffers(1, &vertexBufferId);
/*
第二步
该函数绑定用于指定标识符的缓存到当前缓存
第一个参数:是一个常量,用于指定要绑定哪一种类型的缓存,GL_ARRAY_BUFFER用于指定一个顶点属性数组
第二个参数:绑定缓存的标识符
*/
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId);
/*
第三步
glBufferData()复制应用的顶点数据到当前上下文所绑定的顶点缓存中
第一个参数:指定要更新当前上线文中所绑定的是哪一个缓存
第二个参数:指定要复制进这个缓存的字节数量
第三个参数:要复制的字节的地址
第四个参数:提示缓存在未来的运算中可能被怎样使用
*/
glBufferData(GL_ARRAY_BUFFER,//initialize buffer contents
sizeof(vertices),//number of bytes to copy
vertices, //address of bytes to copy
GL_STATIC_DRAW); // Hint:cache in GPU memory
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
[self.baseEffect prepareToDraw];
glClear(GL_COLOR_BUFFER_BIT);
//第四步:启动渲染操作
glEnableVertexAttribArray(GLKVertexAttribPosition);
/*
第五步
glVertexAttribPointer()告诉OpenGL ES顶点数据在哪里,以及怎么解释为每个顶点保存的数据
第一个参数:指示当前绑定的缓存包含每个顶点的位置信息
第二个参数:指示每个位置有3个部分
第三个参数:告诉OpenGL ES每个部分都保存为浮点类型的值
第四个参数:告诉OpenGL ES小数点固定数据是否可以被改变,本例中没有使用小数点固定的数据,因此这个参数设置为GL_FALSE
第五个参数:指定每个顶点的保存需要多少个字节
第六个参数:告诉OpenGL ES可以从当前绑定的顶点缓存的开始位置访问顶点数据
*/
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(SceneVertex), NULL);
/*
第六步
执行绘图
第一个参数:告诉GPU怎么处理在绑定的顶点缓存内的顶点数据
第二个参数:指定缓存内的需要渲染的第一个顶点的位置
第三个参数:需要渲染的顶点的数量
*/
glDrawArrays(GL_TRIANGLES, 0, 3);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
GLKView *view = (GLKView *)self.view;
[EAGLContext setCurrentContext:view.context];
if (0 != vertexBufferId) {
//第七步:删除不再需要的顶点缓存和上下文
glDeleteBuffers(1, &vertexBufferId);
vertexBufferId = 0;
}
((GLKView *)self.view).context = nil;
[EAGLContext setCurrentContext:nil];
}
@end
网友评论