版本记录
版本号 | 时间 |
---|---|
V1.0 | 2018.08.10 |
前言
GLKit
框架的设计目标是为了简化基于OpenGL或者OpenGL ES的应用开发。 接下来几篇我们就解析一下这个框架。感兴趣的看下面几篇文章。
1. GLKit 框架详细解析(一)—— 基本概览
2. GLKit 框架详细解析(二)—— 一个详细示例和说明(一)
3. GLKit 框架详细解析(三)—— 一个详细示例和说明(二)
示例效果
这个示例是一个旋转的方块,点击就会停止旋转,再次点击就会恢复旋转。
前两篇关于理论等都已经说了很多了,这一篇主要就是给出Swift版本和OC版本的的源码。
Swift源码
下面看一下Swift版的源码。
1. Array+Helpers.swift
import Foundation
//
// MARK: - Array Helpers
//
/// Array extension to help with size/memory calculations when working with OpenGL.
extension Array {
//
// MARK: - Instance Methods
//
/// Returns the momory size/footprint (in bytes) of a given array.
///
/// - Returns: Integer value representing the memory size the array.
func size () -> Int {
return count * MemoryLayout.size(ofValue: self[0])
}
}
2. Vertex.swift
import GLKit
//
// MARK: - Vertex
//
/// Structure to hold a vertex's position and color data.
struct Vertex {
/// Stores the X coordinate of a vertex.
var x: GLfloat
/// Stores the Y coordinate of a vertex.
var y: GLfloat
/// Stores the Z coordinate of a vertex.
var z: GLfloat
/// Stores the red color value of a vertex.
var r: GLfloat
/// Stores the green color value of a vertex.
var g: GLfloat
/// Stores the blue color value of a vertex.
var b: GLfloat
/// Stores the alpha value of a vertex.
var a: GLfloat
}
3. ViewController.swift
import GLKit
//
// MARK: - View Controller
//
/// Our subclass of GLKViewController to perform drawing, and logic updates using OpenGL ES.
final class ViewController: GLKViewController {
/// Vertices array that stores 4 Vertex objects used to draw and color a square on screen.
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),
]
/// Array used to store the indices in the order we want to draw the triangles of our square.
var Indices: [GLubyte] = [
0, 1, 2,
2, 3, 0
]
//
// MARK: - Variables And Properties
//
/// Reference to provide easy access to our EAGLContext.
private var context: EAGLContext?
/// Effect to facilitate having to write shaders in order to achieve shading and lighting.
private var effect = GLKBaseEffect()
/// Used to store and determine the rotation value of our drawn geometry.
private var rotation: Float = 0.0
/// Element buffer object. Stores the indices that tell OpenGL what vertices to draw.
private var ebo = GLuint()
/// Vertex buffer object. Stores our vertex information within the GPU's memory.
private var vbo = GLuint()
/// Vertex array object. Stores vertex attribute calls that facilitate future drawing. Instead of having to bind/unbind
/// several buffers constantly to perform drawn, you can simply bind your VAO, make the vertex attribute cals you would
/// to draw elements on screen, and then whenever you want to draw you simply bind your VAO and it stores those other
/// vertex attribute calls.
private var vao = GLuint()
//
// MARK: - Initialization
//
/// Method to deinitialize and perform cleanup when the view controller is removed from memory.
deinit {
// Delete buffers, cleanup memory, etc.
tearDownGL()
}
//
// MARK: - Private Methods
//
/// Setup the current OpenGL context, generate and find necessary buffers, and store geometry data in memory (buffers).
private func setupGL() {
// Create an OpenGL ES 3.0 context and store it in our local variable.
context = EAGLContext(api: .openGLES3)
// Set the current EAGLContext to our context we created when performing OpenGL setup.
EAGLContext.setCurrent(context)
// Perform checks and unwrap options in order to perform more OpenGL setup.
if let view = self.view as? GLKView, let context = context {
// Set our view's context to the EAGLContext we just created.s
view.context = context
// Set ourselves as delegates of GLKViewControllerDelegate
delegate = self
}
// Helper variables to identify the position and color attributes for OpenGL calls.
let vertexAttribColor = GLuint(GLKVertexAttrib.color.rawValue)
let vertexAttribPosition = GLuint(GLKVertexAttrib.position.rawValue)
// The size, in memory, of a Vertex structure.
let vertexSize = MemoryLayout<Vertex>.stride
// The byte offset, in memory, of our color information within a Vertex object.
let colorOffset = MemoryLayout<GLfloat>.stride * 3
// Swift pointer object that stores the offset of the color information within our Vertex structure.
let colorOffsetPointer = UnsafeRawPointer(bitPattern: colorOffset)
// VAO
// Generate and bind a vertex array object.
glGenVertexArraysOES(1, &vao)
glBindVertexArrayOES(vao)
// VBO
// Generatea a buffer for our vertex buffer object.
glGenBuffers(1, &vbo)
// Bind the vertex buffer object we just generated (created).
glBindBuffer(GLenum(GL_ARRAY_BUFFER), vbo)
// Pass data for our vertices to the vertex buffer object.
glBufferData(GLenum(GL_ARRAY_BUFFER), Vertices.size(), Vertices, GLenum(GL_STATIC_DRAW))
// Enable the position vertex attribute to then specify information about how the position of a vertex is stored.
glEnableVertexAttribArray(vertexAttribPosition)
glVertexAttribPointer(vertexAttribPosition, 3, GLenum(GL_FLOAT), GLboolean(UInt8(GL_FALSE)), GLsizei(vertexSize), nil)
// Enable the colors vertex attribute to then specify information about how the color of a vertex is stored.
glEnableVertexAttribArray(vertexAttribColor)
glVertexAttribPointer(vertexAttribColor, 4, GLenum(GL_FLOAT), GLboolean(UInt8(GL_FALSE)), GLsizei(vertexSize), colorOffsetPointer)
// EBO
// Generatea a buffer for our element buffer object.
glGenBuffers(1, &ebo)
// Bind the element buffer object we just generated (created).
glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), ebo)
// Pass data for our element indices to the element buffer object.
glBufferData(GLenum(GL_ELEMENT_ARRAY_BUFFER), Indices.size(), Indices, GLenum(GL_STATIC_DRAW))
// Unbind all buffers and objects.
// Unbind the vertex buffer and the vertex array object.
glBindBuffer(GLenum(GL_ARRAY_BUFFER), 0)
glBindVertexArrayOES(0)
}
/// Perform cleanup, and delete buffers and memory.
private func tearDownGL() {
// Set the current EAGLContext to our context. This ensures we are deleting buffers against it and potentially not a
// different context.
EAGLContext.setCurrent(context)
// Delete the vertex array object, the element buffer object, and the vertex buffer object.
glDeleteBuffers(1, &vao)
glDeleteBuffers(1, &vbo)
glDeleteBuffers(1, &ebo)
// Set the current EAGLContext to nil.
EAGLContext.setCurrent(nil)
// Then nil out or variable that references our EAGLContext.
context = nil
}
//
// MARK: - Touch Handling
//
/// Used to detect when a tap occurs on screen so we can pause updates of our program.
///
/// - Parameters:
/// - touches: The touches that occurred on screen.
/// - event: Describes the user interactions in the app.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// Pause or unpause updating our program.
isPaused = !isPaused
}
//
// MARK: - View Controller
//
/// Called when the view controller's view is loaded into memory.
override func viewDidLoad() {
super.viewDidLoad()
// Perform OpenGL setup, create buffers, pass geometry data to memory.
setupGL()
}
}
//
// MARK: - GLKViewController Delegate
//
extension ViewController: GLKViewControllerDelegate {
func glkViewControllerUpdate(_ controller: GLKViewController) {
let aspect = fabsf(Float(view.bounds.size.width) / Float(view.bounds.size.height))
let projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0), aspect, 4.0, 10.0)
effect.transform.projectionMatrix = projectionMatrix
var modelViewMatrix = GLKMatrix4MakeTranslation(0.0, 0.0, -6.0)
rotation += 90 * Float(timeSinceLastUpdate)
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, GLKMathDegreesToRadians(rotation), 0, 0, 1)
effect.transform.modelviewMatrix = modelViewMatrix
}
}
//
// MARK: - GLKView Delegate
//
/// Extension to implement the GLKViewDelegate methods.
extension ViewController {
/// Draw the view's contents using OpenGL ES.
///
/// - Parameters:
/// - view: The GLKView object to redraw contents into.
/// - rect: Rectangle that describes the area to draw into.
override func glkView(_ view: GLKView, drawIn rect: CGRect) {
// Set the color we want to clear the screen with (before drawing) to black.
glClearColor(0.85, 0.85, 0.85, 1.0)
// Clear the contents of the screen (the color buffer) with the black color we just set.
glClear(GLbitfield(GL_COLOR_BUFFER_BIT))
// Compiles the shaders for drawing and binds them to the current context.
effect.prepareToDraw()
// We bind our vertex array object, essentially indicating we want to use its information to draw geometry on screen.
glBindVertexArrayOES(vao);
// Make the call to draw elements on screen. We indicate we want to draw triangles, specify the number of vertices we
// want to draw via our indices array, and also tell OpenGL what variable type is used to store the index information.
glDrawElements(GLenum(GL_TRIANGLES), GLsizei(Indices.count), GLenum(GL_UNSIGNED_BYTE), nil)
// Unbind the vertex array object so future calls don't accidentally use it.
glBindVertexArrayOES(0)
}
}
OC源码
下面我们就看一下OC版本的源码。
1. 准备工作
首先删除工程建立时带的ViewController,在控件区找到GLKViewController,拖进去如下所示:
设置sb初始化入口
修改ViewController继承并绑定sb
#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>
@interface ViewController : GLKViewController
@end
将帧率设置为60
这个源码正在写,后续会进行同步更新~~~
后记
本篇主要讲述了一个详细示例和说明,感兴趣的给个赞或者关注~~~~