GLKit 框架详细解析(二)—— 一个详细示例和说明(一)
版本记录
版本号 | 时间 |
---|---|
V1.0 | 2018.08.10 |
前言
GLKit
框架的设计目标是为了简化基于OpenGL或者OpenGL ES的应用开发。 接下来几篇我们就解析一下这个框架。感兴趣的看下面几篇文章。
1. GLKit 框架详细解析(一)—— 基本概览
简介
如果您对图形编程感兴趣,那么您可能已经阅读过OpenGL,它仍然是从硬件和软件角度来看最常用的API。 Apple开发了一个名为GLKit的框架,以帮助开发人员创建利用OpenGL的应用程序并抽象样板代码。 它还允许开发人员专注于绘图,而不是开启项目。 您将在这个适用于iOS的GLKit教程中了解所有这些是如何工作的。
GLKit在以下四个方面提供功能:
- Views and View Controllers - 视图和视图控制器:这些抽象出大部分是GLKit用于设置基本OpenGL ES(嵌入式系统)项目的样板代码。
- Effects - 效果:这些实现了常见的着色行为,是设置基本光照,着色,反射映射和天空盒效果的便捷方式。
- Math - 数学:为常见的数学例程提供帮助和函数,如向量和矩阵操作。
- Texture Loading - 纹理加载:使图像作为要在OpenGL中使用的纹理加载更容易。
注意:您将使用OpenGL ES 3.0,可在iPhone 5S及更高版本,iPad Mini 2及更高版本以及iPad 5及更高版本上使用。
本文章的目标是让您快速了解使用OpenGL和GLKit的基础知识,假设您以前没有任何经验。 您将构建一个应用程序,将立方体绘制到屏幕并使其旋转。
打开Xcode并创建一个全新的项目。 选择iOS \ Application \ Single View App
模板。将产品名称设置为OpenGLKit
,将语言设置为Swift。 确保未选中任何复选框。 单击“下一步”,选择要在其中保存项目的文件夹,然后单击“创建”。
Build并运行。 你会看到一个简单的空白屏幕:
Introducing GLKView and GLKViewController - 引入GLKView和GLKViewController
您需要导入GLKit
,您的view controller
需要是GLKViewController
的子类。
import GLKit
class ViewController: GLKViewController {
}
Interface Builder
支持GLKit
,因此这是设置它的最佳方式。 现在就这样做。
打开Main.storyboard
并删除storyboard
的内容。 然后,从对象库中将GLKit View Controller
拖到scene中。
在Identity
检查器中,将类更改为ViewController
。 在Attributes
检查器中,选中Is Initial View Controller
复选框。
最后,将Preferred FPS
更改为60:
打开Attributes
检查器后,单击画布中的GLKView
,并注意颜色,深度和模板格式以及多重采样multisampling
的一些设置。如果你正在做一些高级的事情,你需要改变这些,本教程使用默认设置就可满足需求。
您的OpenGL上下文有一个缓冲区buffer
,用于存储将显示在屏幕上的颜色。您可以使用Color Format
属性为缓冲区中的每个像素设置颜色格式。
默认值为GLKViewDrawableColorFormatRGBA8888
,这意味着缓冲区中的每个颜色分量使用8位(每个像素总共4个字节)。这是最佳选择,因为它可以为您提供最广泛的颜色范围,这意味着应用程序看起来更高质量。
这就是你在storyboard
中需要做的所有设置。您的视图控制器设置了GLKView
以绘制OpenGL内容,并且它还被设置为GLKViewDelegate
用于更新和绘制调用。
回到ViewController.swift
,添加以下变量和方法:
private var context: EAGLContext?
private func setupGL() {
// 1
context = EAGLContext(api: .openGLES3)
// 2
EAGLContext.setCurrent(context)
if let view = self.view as? GLKView, let context = context {
// 3
view.context = context
// 4
delegate = self
}
}
以下是此方法中发生的情况:
- 1)要使用OpenGL执行任何操作,您需要创建
EAGLContext
。
EAGLContext
管理iOS需要使用OpenGL绘制的所有信息。它类似于需要Core Graphics
上下文与Core Graphics
一起做任何事情。创建上下文时,指定要使用的API版本。在本文中要使用OpenGL ES 3.
0。
- 2)指定刚刚创建的呈现上下文
rendering context
是在当前线程中使用的呈现上下文。
OpenGL上下文不应该跨线程共享,因此您必须确保只从您用来调用此方法setupGL()
的任何线程中与此上下文进行交互。
-
3)这将设置
GLKView
的上下文。解包必要的变量后,将GLKView
的上下文设置为您创建的此OpenGL ES 3.0
上下文。 -
4)这将当前类
(ViewController)
设置为GLKViewController
的代理。每当需要进行状态和逻辑更新时,将调用glkViewControllerUpdate(_ controller :)
方法。
完成此操作后,添加以下内容以实现viewDidLoad()
以调用此方法:
override func viewDidLoad() {
super.viewDidLoad()
setupGL()
}
所以现在你知道哪个线程称为setupGL()
- 它是主线程,它是专门用于与UIKit交互的特殊线程,当系统调用viewDidLoad()
时它被系统使用。
此时,您可能会注意到有错误。 这是因为你还没有遵循GLKViewControllerDelegate
。 继续,通过添加以下扩展名使其符合要求:
extension ViewController: GLKViewControllerDelegate {
func glkViewControllerUpdate(_ controller: GLKViewController) {
}
}
接下来,将以下方法添加到ViewController
主类定义中:
override func glkView(_ view: GLKView, drawIn rect: CGRect) {
// 1
glClearColor(0.85, 0.85, 0.85, 1.0)
// 2
glClear(GLbitfield(GL_COLOR_BUFFER_BIT))
}
这是GLKViewDelegate
的一部分,它在每一帧上绘制内容。 这是它的作用:
-
1)调用
glClearColor
指定清除屏幕时要使用的RGB和alpha(透明度)值。 在这里,你把它设置为浅灰色。 -
2)调用
glClear
来实际执行清除。 可以有不同类型的缓冲区,如您现在正在显示的渲染/颜色render/color
缓冲区,以及其他depth or stencil
缓冲区。 在这里,您使用GL_COLOR_BUFFER_BIT
标志指定要清除当前渲染/颜色render/color
缓冲区。
Build并运行应用程序。 注意屏幕颜色是如何变化的:
Creating Vertex Data for a Simple Square - 为简单方块创建顶点数据
是时候开始在屏幕上画一个正方形的过程了! 首先,您需要创建定义正方形的顶点vertices
。 顶点(多个顶点)只是定义要绘制的形状轮廓的点。
您将按如下方式设置顶点:
只能使用OpenGL
渲染三角形几何体。 但是,您可以创建一个带有两个三角形的正方形,如上图所示:一个三角形顶点(0,1,2)和一个三角形顶点(2,3,0)。
OpenGL ES
的一个好处是你可以保持你的顶点数据有条理。 对于此项目,您将使用Swift结构体来存储顶点位置和颜色信息,然后使用您将用于绘制的每个顶点的顶点数组。
右键单击Project
导航器中的OpenGLKit
文件夹,选择New File ...
转到iOS \ Swift File
,然后单击Next。 将文件命名为Vertex
,然后单击Create
。 用以下内容替换文件的内容:
import GLKit
struct Vertex {
var x: GLfloat
var y: GLfloat
var z: GLfloat
var r: GLfloat
var g: GLfloat
var b: GLfloat
var a: GLfloat
}
对于具有位置(x,y,z)
和颜色(r,g,b,a)
的变量的顶点,这是非常简单的Swift结构体。 GLFloat是Swift Float
的类型别名,但是在使用OpenGL时,它是推荐使用浮点数的方法。 您可能会看到类似的模式,其中您将OpenGL类型用于您创建的其他变量。
返回到ViewController.swift
中。 在控制器中添加以下代码:
var Vertices = [
Vertex(x: 1, y: -1, z: 0, r: 1, g: 0, b: 0, a: 1),
Vertex(x: 1, y: 1, z: 0, r: 0, g: 1, b: 0, a: 1),
Vertex(x: -1, y: 1, z: 0, r: 0, g: 0, b: 1, a: 1),
Vertex(x: -1, y: -1, z: 0, r: 0, g: 0, b: 0, a: 1),
]
var Indices: [GLubyte] = [
0, 1, 2,
2, 3, 0
]
在这里,您使用Vertex
结构体创建用于绘制的顶点数组。 然后,您创建一个GLubyte
值数组。 GLubyte
只是旧的UInt8
的类型别名,此数组指定绘制构成三角形的三个顶点中的每一个的顺序。 也就是说,前三个整数(0,1,2)
表示通过使用第0个,第1个,最后是第2个verex
来绘制第一个三角形。 后三个整数(2,3,0)
表示使用第2个,第3个和第0个顶点绘制第二个三角形。
因为三角形共享顶点,这节省了资源:您只创建一个包含所有四个顶点的数组,然后使用单独的数组通过引用这些顶点来定义三角形。 因为指向顶点的数组索引占用的内存少于顶点本身,所以这可以节省内存。
完成后,您将获得传递给OpenGL
以绘制正方形所需的所有信息。
Creating Vertex Buffer Objects and a Vertex Array Object - 创建顶点缓冲区对象和顶点数组对象
向OpenGL发送数据的最佳方式是通过名为Vertex Buffer Objects
的方法。 这些是OpenGL对象,可以为您存储顶点数据的缓冲区。
这里有三种类型的对象需要注意:
-
Vertex Buffer Object (VBO) - 顶点缓冲区对象(VBO):跟踪每个顶点数据本身,就像
Vertices
数组中的数据一样。 -
Element Buffer Object (EBO) - 元素缓冲区对象(EBO):跟踪定义三角形的索引,例如存储在
Indices
数组中的索引。 -
Vertex Array Object (VAO) - 顶点数组对象(VAO):此对象可以像顶点缓冲区对象一样绑定。 在绑定顶点数组对象之后,您所做的任何未来顶点属性调用都将存储在其中。 这意味着你只需要调用一次配置顶点属性指针然后 - 每当你想绘制一个对象时 - 你绑定相应的VAO。 这有助于并加速绘制具有不同配置的不同顶点数据。
在ViewController.swift
的顶部,添加以下Array
扩展以帮助获取Vertices
和Indices
数组的大小(以字节为单位):
extension Array {
func size() -> Int {
return MemoryLayout<Element>.stride * self.count
}
}
这里一个重要的微妙之处在于,为了确定数组占用的内存,我们需要将其组成元素的步幅stride
加起来,而不是大小size
。 根据定义,元素的步幅是元素在数组中时占用的内存量。 由于填充,这可能比元素的大小更大,这基本上是extra memory that we use up to keep the CPU happy
的技术术语。
接下来,在ViewController
中添加以下变量:
private var ebo = GLuint()
private var vbo = GLuint()
private var vao = GLuint()
这些是元素缓冲区对象,顶点缓冲区对象和顶点数组对象的变量。 所有都是GLuint
类型,UInt32
的类型别名。
后记
本篇主要讲述了一个详细示例和说明,感兴趣的给个赞或者关注~~~~