- (void)viewDidLoad{
[super viewDidLoad];
// 创建OpenGL ES上下⽂并将其分配给从故事板加载的视图
GLKView * view =(GLKView *)self.view;
view.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
// 配置视图创建的渲染缓冲区
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24; view.drawableStencilFormat = GLKViewDrawableStencilFormat8;
// 启⽤多重采样
view.drawableMultisample = GLKViewDrawableMultisample4X;
}
- (void)drawRect:(CGRect)rect {
// 清除帧缓冲区
glClearColor(0.0f,0.0f,0.1f,1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 使⽤先前配置的纹理,着⾊器和顶点数组绘制
glBindTexture(GL_TEXTURE_2D,_planetTexture);
glUseProgram(_diffuseShading);
glUniformMatrix4fv(_uniformModelViewProjectionMatrix,1,0,_modelViewProjectionMatrix.m);
glBindVertexArrayOES(_planetMesh);
glDrawElements(GL_TRIANGLE_STRIP,256,GL_UNSIGNED_SHORT);
}
对于更新阶段,视图控制器调用它自己的更新方法(或它的委托的glkViewControllerUpdate:方法),在这种方法中,应该准备绘制下一帧。例如,游戏可以使用此方法根据自最后一帧以来收到的输入事件来确定玩家和敌人角色的位置,科学可视化可以使用此方法运行模拟的一个步骤。如果需要时间信息来确定你的应用在下一帧的状态,使用一个视图控制器的时间属性,比如timeSinceLastUpdate属性。
使用GLKit视图和视图控制器绘制和动画OpenGL ES内容
- (void)viewDidLoad {
[super viewDidLoad];
// Create an OpenGL ES context and assign it to the view loaded from storyboard
GLKView *view = (GLKView *)self.view;
view.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
// Set animation frame rate
self.preferredFramesPerSecond = 60;
// Not shown: load shaders, textures and vertex arrays, set up projection matrix
[self setupGL];
}
- (void)update {
_rotation += self.timeSinceLastUpdate * M_PI_2; // one quarter rotation per second
// Set up transform matrices for the rotating planet
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeRotation(_rotation, 0.0f, 1.0f, 0.0f);
_normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(modelViewMatrix), NULL);
_modelViewProjectionMatrix = GLKMatrix4Multiply(_projectionMatrix, modelViewMatrix);
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
// Clear the framebuffer
glClearColor(0.0f, 0.0f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Set shader uniforms to values calculated in -update
glUseProgram(_diffuseShading);
glUniformMatrix4fv(_uniformModelViewProjectionMatrix, 1, 0, _modelViewProjectionMatrix.m);
glUniformMatrix3fv(_uniformNormalMatrix, 1, 0, _normalMatrix.m);
// Draw using previously configured texture and vertex array
glBindTexture(GL_TEXTURE_2D, _planetTexture);
glBindVertexArrayOES(_planetMesh);
glDrawElements(GL_TRIANGLE_STRIP, 256, GL_UNSIGNED_SHORT, 0);
}
name : OpenGL 上下⽂中纹理名称
target : 纹理绑定的目标
height : 加载的纹理高度
width : 加载纹理的宽度
textureOrigin : 加载纹理中的原点位置
alphaState: 加载纹理中alpha分量状态
containsMipmaps: 布尔值,加载的纹理是否包含mip贴图
- initWithSharegroup: 初始化⼀个新的纹理加载到对象中
- initWithShareContext: 初始化⼀个新的纹理加载对象
+ textureWithContentsOfFile:options:errer: 从⽂件加载2D纹理图像并从数据中
创建新的纹理
+ textureWithContentsOfFile:options:queue:completionHandler: 从文件中异步
加载2D纹理图像,并根据数据创建新纹理
+ textureWithContentsOfURL:options:error: 从URL加载2D纹理图像并从数据创建新纹理
+ textureWithContentsOfURL:options:queue:completionHandler: 从URL异步加载2D纹理图像,并根据数据创建新纹理
+ textureWithContentsOfData:options:errer: 从内存空间加载2D纹理图像,并根据数据创建新纹理
- textureWithContentsOfData:options:queue:completionHandler:从内存空间异步加载2D纹理图像,并从数据中创建新纹理
- textureWithCGImage:options:error: 从Quartz图像 加载2D纹理图像并从数据创建新纹理
- textureWithCGImage:options:queue:completionHandler: 从Quartz图像异步加载2D纹理图像,并根据数据创建新纹理
+ cabeMapWithContentsOfURL:options:errer: 从单个URL加载⽴方体贴图纹理图像,并根据数据创建新纹理
- cabeMapWithContentsOfURL:options:queue:completionHandler:从单个URL异步加载⽴方体贴图纹理图像,并根据数据创建新纹理
+ cubeMapWithContentsOfFile:options:errer: 从单个文件加载⽴方体贴图纹理对象,并从数据中创建新纹理
- cubeMapWithContentsOfFile:options:queue:completionHandler:从单个文件异步加载⽴方体贴图纹理对象,并从数据中创建新纹理
+ cubeMapWithContentsOfFiles:options:errer: 从⼀系列文件中加载⽴方体贴图纹理图像,并从数据总创建新纹理
- cubeMapWithContentsOfFiles:options:options:queue:completionHandler:从⼀系列⽂件异步加载⽴方体贴图纹理图像,并从数据中创建新纹理
- initWithFrame:context: 初始化新视图
delegate 视图的代理
drawableColorFormat 颜⾊色渲染缓存区格式
drawableDepthFormat 深度渲染缓存区格式
drawableStencilFormat 模板渲染缓存区的格式
drawableMultisample 多重采样缓存区的格式
drawableHeight 底层缓存区对象的高度(以像素为单位)
drawableWidth 底层缓存区对象的宽度(以像素为单位)
context 绘制视图内容时使用的OpenGL ES上下⽂
- bindDrawable 将底层FrameBuffer对象绑定到OpenGL ES
enableSetNeedsDisplay 布尔值,指定视图是否响应使得视图内容无效的消息
- display ⽴即重绘视图内容
snapshot 绘制视图内容并将其作为新图像对象返回
- deleteDrawable 删除与视图关联的可绘制对象
- glkView:drawInRect: 绘制视图内容 (必须实现代理)
- (void) update 更新视图内容
- (void) glkViewControllerUpdate:
preferredFramesPerSecond 视图控制器调用视图以及更新视图内容的速率
framesPerSencond 视图控制器调⽤视图以及更新其内容的实际速率
delegate 视图控制器的代理
paused 布尔值,渲染循环是否已暂停
pausedOnWillResignActive 布尔值,当前程序重新激活动状态时视图控制器是否⾃动暂停渲染循环
resumeOnDidBecomeActive 布尔值,当前程序变为活动状态时视图控制是否自动恢复呈现循
frameDisplayed 视图控制器自创建以来发送的帧更新数
timeSinceFirstResume ⾃视图控制器第一次恢复发送更新事件以来经过的时间量
timeSinceLastResume 自上次视图控制器恢复发送更新事件以来更更新的时间量
timeSinceLastUpdate ⾃上次视图控制器调用委托方法以及经过的时间量
glkViewControllerUpdate:
timeSinceLastDraw ⾃上次视图控制器调用视图display方法以来经过的时间量
- glkViewControllerUpdate: 在显示每个帧之前调⽤
- glkViewController:willPause: 在渲染循环暂停或恢复之前调⽤
label 给Effect(效果)命名
transform 绑定效果时应⽤于顶点数据的模型视图,投影和纹理变换
lightingType ⽤于计算每个片段的光照策略,GLKLightingType
GLKLightingType
GLKLightingTypePerVertex 表示在三角形中每个顶点执行光照计算,然后在三角形进⾏插值
GLKLightingTypePerPixel 表示光照计算的输入在三角形内插入,并且在每个片段执⾏光照计算
lightModelTwoSided 布尔值,表示为基元的两侧计算光照
material 计算渲染图元光照使用的材质属性
lightModelAmbientColor 环境颜色,应⽤效果渲染的所有图元.
light0 场景中第⼀个光照属性
light1 场景中第二个光照属性
light2 场景中第三个光照属性
texture2d0 第一个纹理属性
texture2d1 第⼆个纹理属性
textureOrder 纹理应用于渲染图元的顺序
fog 应⽤于场景的雾属性
colorMaterialEnable 布尔值,表示计算光照与材质交互时是否使用颜⾊顶点属性
useConstantColor 布尔值,指示是否使⽤用常量颜色
constantColor 不提供每个顶点颜⾊数据时使⽤常量颜⾊
- prepareToDraw 准备渲染效果
简单渲染加载一张jpg/png图片:
/* 初始化上下文并设置当前上下文
* EAGLContext 是苹果iOS平台下实现OpenGLES 渲染层
* kEAGLRenderingAPIOpenGLES1 = 1, 固定管线
* kEAGLRenderingAPIOpenGLES2 = 2,
* kEAGLRenderingAPIOpenGLES3 = 3,
*/
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
// 判断是否创建成功
if (!context) {
NSLog(@"Creat failed");
}
// 设置上下文
[EAGLContext setCurrentContext:context];
OpenGL ES 有一个缓存区,它用以存储将在屏幕中显示的颜色,可以使用其属性来设置缓冲区中的每个像素的颜色格式。drawableColorFormat: 颜色缓存区格式:
GLKViewDrawableColorFormatRGBA8888 = 0;默认缓存区的每个像素的最小组成部分(RGBA)使用8个bit(故每个像素4个字节,4*8个bit)GLKViewDrawableColorFormatRGB565:如果APP允许更小范围的颜色,即可设置这个,会让APP消耗更小的资源(内存和处理时间)
drawableDepthFormat: 深度缓存区格式
GLKViewDrawableDepthFormatNone = 0,意味着完全没有深度缓冲区
GLKViewDrawableDepthFormat16,
GLKViewDrawableDepthFormat24,
如果要使用这个属性(一般用于3D游戏),应该选择GLKViewDrawableDepthFormat16
或GLKViewDrawableDepthFormat24,差别就是使用GLKViewDrawableDepthFormat16将 消耗更少的资源。
// 设置上下文
[EAGLContext setCurrentContext:context];
// 获取GLKView 设置context
GLKView *view = (GLKView *)self.view;
view.context = context;
// 配置视图创建的渲染缓存区
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
/* 设置顶点数组(顶点坐标,纹理坐标)
* 纹理坐标系取值范围[0,1];原点是左下角(0,0);
* 故(0,0)是纹理图像的左下角, 点(1,1)是右上角.
*/
GLfloat vertexData[] = {
0.5, -0.5, 0.0f, 1.0f, 0.0f, // 右下
0.5, 0.5, 0.0f, 1.0f, 1.0f, // 右上
-0.5, 0.5, 0.0f, 0.0f, 1.0f, // 左上
0.5, -0.5, 0.0f, 1.0f, 0.0f, // 右下
-0.5, 0.5, 0.0f, 0.0f, 1.0f, // 左上
-0.5, -0.5, 0.0f, 0.0f, 0.0f, // 左下
};
/* 顶点数组:可以选择设定函数指针,在调用绘制方法的时候,直接由内存传入顶点数据
* 也就是说这部分数据之前是存储在内存当中的,被称为顶点数组
*
* 顶点缓存区: 性能更高的做法是,提前分配一块显存,将顶点数据预先传入到显存当中
* 这部分的显存,就被称为顶点缓冲区
*/
// 开辟顶点缓存区
GLuint bufferID;
// 创建顶点缓存区标识符ID
glGenBuffers(1, &bufferID);
// 绑定顶点缓存区
glBindBuffer(GL_ARRAY_BUFFER, bufferID);
// 将顶点数组的数据copy到顶点缓存区中(GPU显存中)
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
/* glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
* 功能:上传顶点数据到显存的方法(设置合适的方式从buffer里面读取数据)
* index:指定要修改的顶点属性的索引值
* size:每次读取数量(如position是由3个(x,y,z)组成,而颜色是4个(r,g,b,a),纹理则是2个)
* type:指定数组中每个组件的数据类型。可用的符号常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED, 和 GL_FLOAT,初始值为GL_FLOAT。
* normalized:指定当被访问时,固定点数据值是否应该被归一化(GL_TRUE)或者直接转换为固定点值(GL_FALSE)
* stride:指定连续顶点属性之间的偏移量。如果为0,那么顶点属性会被理解为:它们是紧密排列在一起的。初始值为0
* ptr:指定一个指针,指向数组中第一个顶点属性的第一个组件。初始值为0
*/
// 顶点坐标数据
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 0);
// 纹理坐标数据
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 3);
// 获取纹理图片路径
NSString *name = [[NSBundle mainBundle] pathForResource:@"祎祎美女" ofType:@"jpg"];
// 设置纹理参数:纹理坐标原点是左下角,但是图片显示原点应该是左上角
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:@(1),GLKTextureLoaderOriginBottomLeft, nil];
GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:name options:options error:nil];
// 使用苹果GLKit 提供GLKBaseEffect 完成着色器工作(顶点/片元)
effect = [[GLKBaseEffect alloc] init];
effect.texture2d0.enabled = GL_TRUE;
effect.texture2d0.name = textureInfo.name;
/* 绘制视图的内容
* GLKView对象使其OpenGL ES上下文成为当前上下文,并将其framebuffer绑定为OpenGL ES呈现命令的目标,然后委托方法应该绘制视图的内容
*/
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
glClear(GL_COLOR_BUFFER_BIT);
[effect prepareToDraw];
glDrawArrays(GL_TRIANGLES, 0, 6);
}
// 透视投影矩阵
CGFloat aspect = fabs(self.view.bounds.size.width / self.view.bounds.size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0), aspect, 0.1, 100.0);
effect.transform.projectionMatrix = projectionMatrix;
// 向后(屏幕里面)平移4.0
GLKMatrix4 modelviewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0, 0, -4.0);
effect.transform.modelviewMatrix = modelviewMatrix;
OpenGL ES之加载一张图片的简单实现