美文网首页iOS图形:Metal、OpenGL、OpenCV、Core Image、Core Graphics
GLKit 框架详细解析(四)—— 一个详细示例和说明(三)

GLKit 框架详细解析(四)—— 一个详细示例和说明(三)

作者: 刀客传奇 | 来源:发表于2018-08-10 12:28 被阅读42次

    版本记录

    版本号 时间
    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

    这个源码正在写,后续会进行同步更新~~~

    后记

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

    相关文章

      网友评论

        本文标题:GLKit 框架详细解析(四)—— 一个详细示例和说明(三)

        本文链接:https://www.haomeiwen.com/subject/qhtkbftx.html