GLKit框架是苹果为快速实现OpenGL ES功能所提供的轻型框架
GLKit框架提供的函数和类减少了创建新的基于着色器的应用程序,减少了现有app所需的依赖于OpenGL ES或OpenGL早期版本提供的顶点着色器或者片元着色器程序的工作。
GLKit主要提供了一下四方面的功能:
1纹理加载让你很容易的从资源文件中加载纹理图片,仅通过几行简单的代码就能让你在后台线程一步加载纹理,更多详细内容请看GLKTextureLoader
2.数学库提供了常用的向量、四元数和矩阵运算。这些实现进行了优化,以提供出色的性能。
3Effects类提供了通用着色效果的标准实现。您可以配置效果和关联的顶点数据;effect将会自动创建并加载一个适当的着色器,GLKit包含三个效果:GLKBaseEffect类实现了OpenGL ES1.1中明暗模型的一个关键子集,GLKReflectionMapEffect类扩展了基本效果以包含反射映射支持,而GLKSkyboxEffect类提供了一个skybox效果的实现。
4.视图和视图控制器提供了OpenGL ES视图和相应视图控制器的标准实现。这减少了创建使用OpenGL ES的iOS应用程序所需的代码量。有关更多信息,请参见GLKView和GLKViewController。
详情请看苹果官方文档:https://developer.apple.com/documentation/glkit
下面介绍如何使用GLKit加载一张纹理图片
// // ViewController.swift // GLKitTest // // Created by dzq_mac on 2020/5/14. // Copyright © 2020 dzq_mac. All rights reserved. // import UIKit import GLKit @available(*, deprecated, message: "ios13")//消除警告 class ViewController: UIViewController { var glView:GLKView! var context:EAGLContext? var effect:GLKBaseEffect! var bufferID : GLuint = GLuint() override func viewDidLoad() { super.viewDidLoad() //1.初始化 config() //2.顶点/纹理 坐标 setUpVertexData() //设置纹理数据 setImage() } func config(){ //1创建GKLKView glView = GLKView(frame: CGRect(x: 20, y: 100, UIScreen.main.bounds.width - 40, height: self.view.bounds.size.height - 200)) self.view.addSubview(glView) //2.设置Context context = EAGLContext(api: EAGLRenderingAPI.openGLES3) if let con = context { EAGLContext.setCurrent(con) glView.context = con } /*3.配置视图创建的渲染缓存区. (1). drawableColorFormat: 颜色缓存区格式. 简介: OpenGL ES 有一个缓存区,它用以存储将在屏幕中显示的颜色。你可以使用其属性来设置缓冲区中的每个像素的颜色格式。 GLKViewDrawableColorFormatRGBA8888 = 0, 默认.缓存区的每个像素的最小组成部分(RGBA)使用8个bit,(所以每个像素4个字节,4*8个bit)。 GLKViewDrawableColorFormatRGB565, 如果你的APP允许更小范围的颜色,即可设置这个。会让你的APP消耗更小的资源(内存和处理时间) (2). drawableDepthFormat: 深度缓存区格式 GLKViewDrawableDepthFormatNone = 0,意味着完全没有深度缓冲区 GLKViewDrawableDepthFormat16, GLKViewDrawableDepthFormat24, 如果你要使用这个属性(一般用于3D游戏),你应该选择GLKViewDrawableDepthFormat16 或GLKViewDrawableDepthFormat24。这里的差别是使用GLKViewDrawableDepthFormat16 将消耗更少的资源 */ glView.drawableColorFormat = .RGBA8888 glView.drawableDepthFormat = .format16 glView.delegate = self //4.设置背景颜色 glClearColor(1, 1, 0, 1) } func setUpVertexData(){ //1.设置顶点数组(顶点坐标,纹理坐标) /* 纹理坐标系取值范围[0,1];原点是左下角(0,0); 故而(0,0)是纹理图像的左下角, 点(1,1)是右上角. */ let vertexs:[GLfloat] = [ 0.5, -0.5, 0.0, 1.0, 0.0, //右下 0.5, 0.5, -0.0, 1.0, 1.0, //右上 -0.5, 0.5, 0.0, 0.0, 1.0, //左上 0.5, -0.5, 0.0, 1.0, 0.0, //右下 -0.5, 0.5, 0.0, 0.0, 1.0, //左上 -0.5, -0.5, 0.0, 0.0, 0.0, //左下 ] /* 顶点数组: 开发者可以选择设定函数指针,在调用绘制方法的时候,直接由内存传入顶点数据,也就是说这部分数据之前是存储在内存当中的,被称为顶点数组 顶点缓存区: 性能更高的做法是,提前分配一块显存,将顶点数据预先传入到显存当中。这部分的显存,就被称为顶点缓冲区 */ ////2.开辟顶点缓存区 //(1).创建顶点缓存区标识符ID glGenBuffers(1, &bufferID) //(2).绑定顶点缓存区.(明确作用) glBindBuffer(GLenum(GL_ARRAY_BUFFER), bufferID) let size = MemoryLayout<[GLfloat]>.size * 30 glBufferData(GLenum(GL_ARRAY_BUFFER), size, vertexs, GLenum(GL_STATIC_DRAW)) //3.打开读取通道. /* (1)在iOS中, 默认情况下,出于性能考虑,所有顶点着色器的属性(Attribute)变量都是关闭的. 意味着,顶点数据在着色器端(服务端)是不可用的. 即使你已经使用glBufferData方法,将顶点数据从内存拷贝到顶点缓存区中(GPU显存中). 所以, 必须由glEnableVertexAttribArray 方法打开通道.指定访问属性.才能让顶点着色器能够访问到从CPU复制到GPU的数据. 注意: 数据在GPU端是否可见,即,着色器能否读取到数据,由是否启用了对应的属性决定,这就是glEnableVertexAttribArray的功能,允许顶点着色器读取GPU(服务器端)数据。 (2)方法简介 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(GLuint(GLKVertexAttrib.position.rawValue)) glVertexAttribPointer(GLuint(GLKVertexAttrib.position.rawValue), 3, GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(MemoryLayout<GLfloat>.size * 5), UnsafeRawPointer(bitPattern: 0)) // glEnableVertexAttribArray(GLuint(GLKVertexAttrib.texCoord0.rawValue)) glVertexAttribPointer(GLuint(GLKVertexAttrib.texCoord0.rawValue), 2, GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(MemoryLayout<GLfloat>.size * 5), UnsafeRawPointer(bitPattern: MemoryLayout<GLfloat>.size * 3)) } func setImage() { guard let imagePath = Bundle.main.path(forResource: "timg", ofType: "jpeg", inDirectory: nil), let image = UIImage(contentsOfFile: imagePath)?.cgImage else { return } let texture = try? GLKTextureLoader.texture(with: image, options: [GLKTextureLoaderOriginBottomLeft:true,GLKTextureLoaderGrayscaleAsAlpha:true,GLKTextureLoaderApplyPremultiplication:true]) effect = GLKBaseEffect() if let textureInfo = texture{ effect.texture2d0.enabled = GLboolean(GL_TRUE) effect.texture2d0.name = textureInfo.name } } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { //present(GLKViewController(), animated: true, completion: nil) } deinit { glDeleteBuffers(1, &bufferID) } } //绘制视图的内容 /* GLKView对象使其OpenGL ES上下文成为当前上下文,并将其framebuffer绑定为OpenGL ES呈现命令的目标。然后,委托方法应该绘制视图的内容。 */ @available(*, deprecated, message: "ios13") extension ViewController :GLKViewDelegate{ func glkView(_ view: GLKView, drawIn rect: CGRect) { glClear(GLbitfield(GL_COLOR_BUFFER_BIT)) effect.prepareToDraw() glDrawArrays(GLenum(GL_TRIANGLES), 0, 6) } }