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及更高版本上使用。

GLKit 框架详细解析(二)—— 一个详细示例和说明(一)_第1张图片

本文章的目标是让您快速了解使用OpenGL和GLKit的基础知识,假设您以前没有任何经验。 您将构建一个应用程序,将立方体绘制到屏幕并使其旋转。

打开Xcode并创建一个全新的项目。 选择iOS \ Application \ Single View App模板。将产品名称设置为OpenGLKit,将语言设置为Swift。 确保未选中任何复选框。 单击“下一步”,选择要在其中保存项目的文件夹,然后单击“创建”。

Build并运行。 你会看到一个简单的空白屏幕:

GLKit 框架详细解析(二)—— 一个详细示例和说明(一)_第2张图片

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:

GLKit 框架详细解析(二)—— 一个详细示例和说明(一)_第3张图片

打开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 :)方法。

完成此操作后,添加以下内容以实现vi​​ewDidLoad()以调用此方法:

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并运行应用程序。 注意屏幕颜色是如何变化的:

GLKit 框架详细解析(二)—— 一个详细示例和说明(一)_第4张图片

Creating Vertex Data for a Simple Square - 为简单方块创建顶点数据

是时候开始在屏幕上画一个正方形的过程了! 首先,您需要创建定义正方形的顶点vertices。 顶点(多个顶点)只是定义要绘制的形状轮廓的点。

您将按如下方式设置顶点:

GLKit 框架详细解析(二)—— 一个详细示例和说明(一)_第5张图片

只能使用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扩展以帮助获取VerticesIndices数组的大小(以字节为单位):

extension Array {
  func size() -> Int {
    return MemoryLayout.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的类型别名。

后记

本篇主要讲述了一个详细示例和说明,感兴趣的给个赞或者关注~~~~

GLKit 框架详细解析(二)—— 一个详细示例和说明(一)_第6张图片

你可能感兴趣的:(GLKit 框架详细解析(二)—— 一个详细示例和说明(一))