效果:
GLKit框架
GLKit功能
1、 加载纹理
2、 提供高性能的数学计算
3、 提供常见着色器
4、 提供视图以及视图控制器
以下介绍GLK库的常用类,扩展查询阅读GLK官方文献资料
1. 加载纹理
GLKTextureLoader:GLK纹理加载器
,可简化从各种图像文件格式中加载OpenGL或OpenGL ES纹理数据的过程。
初始化
//初始化⼀个新的纹理加载到对象中
-initWithSharegroup:
//初始化⼀个新的纹理加载对象
-initWithShareContext:
加载
//从⽂件加载2D纹理图像并从数据中创建新的纹理
+ textureWithContentsOfFile:options:errer:
//从⽂件中异步加载2D纹理图像,并根据数据创建新纹理
-textureWithContentsOfFile:options:queue:completionHandler:
纹理信息GLKTextureInfo
加载后返回的纹理信息
- name:OpenGL上下⽂中纹理名称,标识符的作用
- target:纹理绑定的⽬标
- height:加载的纹理高度
- width:记载的纹理宽度
- textureOrigin:记载的纹理原点的位置
- alphaState:加载的纹理中alpha组件状态
- containsMipmaps:加载的纹理是否包含mip贴图(BOOL)
2.GLKBaseEffect基础着色器
一个简单的照明和着色系统,可用于基于着色器的OpenGL渲染
- label:给Effect(效果)命名
transform
:绑定效果后,将模型视图,投影和纹理转换应用于顶点数据。- lightingType:⽤于计算每个⽚段的光照策略
GLKLightingType
//表示在三⻆形中每个顶点执⾏光照计算,然后在三⻆形进⾏插值
GLKLightingTypePerVertex
//表示光照计算的输⼊在三⻆形内插⼊,并且在每个⽚段执⾏光照计算
GLKLightingTypePerPixel
- material:计算渲染图元光照使⽤的材质属性
- lightModelAmbientColor:环境颜⾊,应⽤效果渲染的所有图元.
light0,light1,light2
:场景中最多三个光照属性
light0.enabled:是否打开光照
light0.diffuseColor:光照漫反射颜色
light0.position:光照位置
texture2d0,texture2d1
:最多两个纹理属性- textureOrder:纹理应⽤于渲染图元的顺序
- fog:应⽤于场景的雾属性
- colorMaterialEnable:布尔值,表示计算光照与材质交互时是否使⽤颜⾊顶点属性
- useConstantColor:布尔值,指示是否使⽤常量颜⾊(黑色)
- constantColor:不提供每个顶点颜⾊数据时使⽤常量颜⾊
- prepareToDraw
:准备渲染效果函数
3.视图和视图控制器
GLKView
使用OpenGL ES绘制内容的默认视图,通过直接代表开发者管理帧缓冲区对象,简化了创建OpenGL ES应用程序所需的工作量,当需要更新时,只需要draw到帧缓冲区即可。
初始化
// 初始化frame,context上下文
-initWithFrame:context:
代理
必须用到的代理方法是
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
配置帧缓冲区对象
- drawableColorFormat:颜⾊渲染缓存区格式
GLKViewDrawableColorFormatRGBA8888,
GLKViewDrawableColorFormatRGB565,
GLKViewDrawableColorFormatSRGBA8888,
- drawableDepthFormat:深度渲染缓存区格式
深度缓冲区的精度
GLKViewDrawableDepthFormatNone,
GLKViewDrawableDepthFormat16,
GLKViewDrawableDepthFormat24,
- drawableStencilFormat:模板渲染缓存区的格式
- drawableMultisample:多重采样缓存区的格式
帧缓冲区属性
创建帧缓冲区的宽高,一般与屏幕对应
- drawableHeight:底层缓存区对象的⾼度(以像素为单位)
- drawableWidth底层缓存区对象的宽度(以像素为单位)
绘制视图的内容
- context:绘制视图内容时使用的OpenGL ES上下文
- -bindDrawable:将底层FrameBuffer对象绑定到OpenGLES
- enableSetNeedsDisplay:布尔值,指定视图是否响应使得视图内容⽆效的消息
- -display:⽴即重绘视图内容
- snapshot:绘制视图内容并将其作为新图像对象返回
删除视图FrameBuffer对象
-deleteDrawable删除与视图关联的可绘制对象
GLKViewController
管理OpenGL ES渲染循环的视图控制器
注意:
当您将view属性设置为指向GLKView对象时,如果视图尚无委托,则视图控制器将自动设置为视图的委托。
更新
- -(void)update:更新视图内容
- -(void)glkViewControllerUpdate:同上
配置帧速率
- preferredFramesPerSecond:视图控制器调⽤视图以及更新视图内容的速率(例如:60帧/s)
- framesPerSencond:视图控制器调⽤视图以及更新其内容的实际速率
代理
- -glkViewControllerUpdate:在显示每帧之前调用
- -glkViewController:willPause:在渲染循环暂停或恢复之前调⽤
控制帧更新
- paused:布尔值,渲染循环是否已暂停
- pausedOnWillResignActive:布尔值,当前程序重新激活活动状态时视图控制器是否自动暂停渲染循环
- resumeOnDidBecomeActive:布尔值,当前程序变为活动状态时视图控制是否⾃动恢复呈现循环
案例:旋转立方体
1.创建OpenGL上下文
// 创建上下文
EAGLContext *context = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
// 设置为 当前上下文
[EAGLContext setCurrentContext:context];
2.初始化GLKView
CGRect frame = CGRectMake(0, 100, self.view.frame.size.width, self.view.frame.size.width);
self.glkView = [[GLKView alloc]initWithFrame:frame context:context];
self.glkView.delegate = self;
self.glkView.backgroundColor = [UIColor clearColor];
[self.view addSubview:self.glkView];
// glkView 深度测试精度
self.glkView.drawableDepthFormat = GLKViewDrawableDepthFormat24;
// 深度缓冲区的范围
glDepthRangef(1, 0);
3.获取图片纹理信息
// 图片地址
NSString *filePath = [[NSBundle mainBundle]pathForResource:@"timg1.jpg" ofType:@""];
UIImage *image = [UIImage imageWithContentsOfFile:filePath];
// 图片变成纹理(位图),获取纹理信息TextureInfo
// 纹理坐标的原点是在左下角,而图片显示的原点在左上,这里需要进行调整,以免渲染出来的结果是倒的
NSDictionary *dic = @{GLKTextureLoaderOriginBottomLeft:@(YES)};
GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithCGImage:[image CGImage] options:dic error:nil];
4.初始化着色器
// effect 着色器
self.baseEffect = [[GLKBaseEffect alloc]init];
self.baseEffect.texture2d0.name = textureInfo.name;
self.baseEffect.texture2d0.target = textureInfo.target;
// 添加光照
self.baseEffect.light0.enabled = YES;
self.baseEffect.light0.diffuseColor = GLKVector4Make(1, 1, 1, 1); // 漫反射颜色
self.baseEffect.light0.position = GLKVector4Make(-0.5, -0.5, 5, 1); // 光照位置
5.顶点&纹理坐标,法线数据
// 开辟顶点数据空间(数据结构SenceVertex 大小 * 顶点个数kCoordCount)
self.vertices = malloc(sizeof(VertexData) * kCoordCount);
// 前面
self.vertices[0] = (VertexData){{-0.5, 0.5, 0.5}, {0, 1}, {0, 0, 1}};
self.vertices[1] = (VertexData){{-0.5, -0.5, 0.5}, {0, 0}, {0, 0, 1}};
self.vertices[2] = (VertexData){{0.5, 0.5, 0.5}, {1, 1}, {0, 0, 1}};
self.vertices[3] = (VertexData){{-0.5, -0.5, 0.5}, {0, 0}, {0, 0, 1}};
self.vertices[4] = (VertexData){{0.5, 0.5, 0.5}, {1, 1}, {0, 0, 1}};
self.vertices[5] = (VertexData){{0.5, -0.5, 0.5}, {1, 0}, {0, 0, 1}};
// 上面
self.vertices[6] = (VertexData){{0.5, 0.5, 0.5}, {1, 1}, {0, 1, 0}};
self.vertices[7] = (VertexData){{-0.5, 0.5, 0.5}, {0, 1}, {0, 1, 0}};
self.vertices[8] = (VertexData){{0.5, 0.5, -0.5}, {1, 0}, {0, 1, 0}};
self.vertices[9] = (VertexData){{-0.5, 0.5, 0.5}, {0, 1}, {0, 1, 0}};
self.vertices[10] = (VertexData){{0.5, 0.5, -0.5}, {1, 0}, {0, 1, 0}};
self.vertices[11] = (VertexData){{-0.5, 0.5, -0.5}, {0, 0}, {0, 1, 0}};
// 下面
self.vertices[12] = (VertexData){{0.5, -0.5, 0.5}, {1, 1}, {0, -1, 0}};
self.vertices[13] = (VertexData){{-0.5, -0.5, 0.5}, {0, 1}, {0, -1, 0}};
self.vertices[14] = (VertexData){{0.5, -0.5, -0.5}, {1, 0}, {0, -1, 0}};
self.vertices[15] = (VertexData){{-0.5, -0.5, 0.5}, {0, 1}, {0, -1, 0}};
self.vertices[16] = (VertexData){{0.5, -0.5, -0.5}, {1, 0}, {0, -1, 0}};
self.vertices[17] = (VertexData){{-0.5, -0.5, -0.5}, {0, 0}, {0, -1, 0}};
// 左面
self.vertices[18] = (VertexData){{-0.5, 0.5, 0.5}, {1, 1}, {-1, 0, 0}};
self.vertices[19] = (VertexData){{-0.5, -0.5, 0.5}, {0, 1}, {-1, 0, 0}};
self.vertices[20] = (VertexData){{-0.5, 0.5, -0.5}, {1, 0}, {-1, 0, 0}};
self.vertices[21] = (VertexData){{-0.5, -0.5, 0.5}, {0, 1}, {-1, 0, 0}};
self.vertices[22] = (VertexData){{-0.5, 0.5, -0.5}, {1, 0}, {-1, 0, 0}};
self.vertices[23] = (VertexData){{-0.5, -0.5, -0.5}, {0, 0}, {-1, 0, 0}};
// 右面
self.vertices[24] = (VertexData){{0.5, 0.5, 0.5}, {1, 1}, {1, 0, 0}};
self.vertices[25] = (VertexData){{0.5, -0.5, 0.5}, {0, 1}, {1, 0, 0}};
self.vertices[26] = (VertexData){{0.5, 0.5, -0.5}, {1, 0}, {1, 0, 0}};
self.vertices[27] = (VertexData){{0.5, -0.5, 0.5}, {0, 1}, {1, 0, 0}};
self.vertices[28] = (VertexData){{0.5, 0.5, -0.5}, {1, 0}, {1, 0, 0}};
self.vertices[29] = (VertexData){{0.5, -0.5, -0.5}, {0, 0}, {1, 0, 0}};
// 后面
self.vertices[30] = (VertexData){{-0.5, 0.5, -0.5}, {0, 1}, {0, 0, -1}};
self.vertices[31] = (VertexData){{-0.5, -0.5, -0.5}, {0, 0}, {0, 0, -1}};
self.vertices[32] = (VertexData){{0.5, 0.5, -0.5}, {1, 1}, {0, 0, -1}};
self.vertices[33] = (VertexData){{-0.5, -0.5, -0.5}, {0, 0}, {0, 0, -1}};
self.vertices[34] = (VertexData){{0.5, 0.5, -0.5}, {1, 1}, {0, 0, -1}};
self.vertices[35] = (VertexData){{0.5, -0.5, -0.5}, {1, 0}, {0, 0, -1}};
6.将顶点数据从内存Copy到帧缓冲区
// 数据copy到帧缓冲区
// 分配
glGenBuffers(1, &_vertexBuffer);
// 绑定
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(VertexData) * 36, self.vertices, GL_STREAM_DRAW);
// 10.把数据从帧缓冲区 读取到GLKit中的着色器
// 顶点数据
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), NULL+offsetof(VertexData, positionCoord));
// 纹理
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), NULL+offsetof(VertexData, textureCoord));
// 法线
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), NULL+offsetof(VertexData, normal));
7.添加定时器
// 添加定时器
- (void)addCADisplayLink{
self.angle = 0;
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(timeUpdate)];
[self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
- (void)timeUpdate{
// 1.计算旋转的角度
self.angle = (self.angle + 1) % 360;
// 渲染 会调用到代理中
[self.glkView display];
}
8.代理方法进行渲染
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 打开深度测试
glEnable(GL_DEPTH_TEST);
// 准备渲染
[self.baseEffect prepareToDraw];
// 旋转
GLKMatrix4 modelviewMatrix = GLKMatrix4Rotate(GLKMatrix4Identity, GLKMathDegreesToRadians(self.angle), 0.3, 0.4, 0.7);
self.baseEffect.transform.modelviewMatrix = modelviewMatrix;
// 正式绘制,
//三角形绘制方式/从0顶点开始/顶点数
glDrawArrays(GL_TRIANGLES, 0, kCoordCount);
}