版本记录
版本号 | 时间 |
---|---|
V1.0 | 2019.01.19 星期六 |
前言
源码
1. Swift
OpenGL源码
首先看下工程组织结构
接着看一下sb文件
下面就是源码了
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 memory 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
final class ViewController: GLKViewController {
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]
private var context: EAGLContext?
private var effect = GLKBaseEffect()
private var rotation: Float = 0.0
private var ebo = GLuint()
private var vbo = GLuint()
private var vao = GLuint()
deinit {
tearDownGL()
}
private func setupGL() {
context = EAGLContext(api: .openGLES3)
EAGLContext.setCurrent(context)
if let view = view as? GLKView, let context = context {
view.context = context
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
let colorOffset = MemoryLayout<GLfloat>.stride * 3
let colorOffsetPointer = UnsafeRawPointer(bitPattern: colorOffset)
// VAO
// Generate and bind a vertex array object.
glGenVertexArraysOES(1, &vao)
glBindVertexArrayOES(vao)
// VBO
glGenBuffers(1, &vbo)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), vbo)
glBufferData(GLenum(GL_ARRAY_BUFFER), Vertices.size(), Vertices, GLenum(GL_STATIC_DRAW))
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
glGenBuffers(1, &ebo)
glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), ebo)
glBufferData(GLenum(GL_ELEMENT_ARRAY_BUFFER), Indices.size(), Indices, GLenum(GL_STATIC_DRAW))
glBindBuffer(GLenum(GL_ARRAY_BUFFER), 0)
glBindVertexArrayOES(0)
}
/// Perform cleanup, and delete buffers and memory.
private func tearDownGL() {
EAGLContext.setCurrent(context)
glDeleteBuffers(1, &vao)
glDeleteBuffers(1, &vbo)
glDeleteBuffers(1, &ebo)
EAGLContext.setCurrent(nil)
context = nil
}
override func viewDidLoad() {
super.viewDidLoad()
setupGL()
}
}
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
}
override func glkView(_ view: GLKView, drawIn rect: CGRect) {
glClearColor(0.85, 0.85, 0.85, 1.0)
glClear(GLbitfield(GL_COLOR_BUFFER_BIT))
effect.prepareToDraw()
glBindVertexArrayOES(vao)
glDrawElements(GLenum(GL_TRIANGLES), GLsizei(Indices.count), GLenum(GL_UNSIGNED_BYTE), nil)
glBindVertexArrayOES(0)
}
}
下面看一下实现效果
Metal源码
首先还是看下工程组织结构
接着看sb中的内容
下面就是源码了
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 memory 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
}
struct SceneMatrices {
var projectionMatrix: GLKMatrix4 = GLKMatrix4Identity
var modelviewMatrix: GLKMatrix4 = GLKMatrix4Identity
}
3. ViewController.swift
import GLKit
import MetalKit
final class ViewController: UIViewController {
@IBOutlet weak var metalView: MTKView!
private var vertexBuffer: MTLBuffer!
private var indicesBuffer: MTLBuffer!
private var metalDevice: MTLDevice!
private var metalCommandQueue: MTLCommandQueue!
private var pipelineState: MTLRenderPipelineState!
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: [UInt32] = [0, 1, 2, 2, 3, 0]
private var rotation: Float = 0.0
private var ebo = GLuint()
private var vbo = GLuint()
private var vao = GLuint()
private var sceneMatrices = SceneMatrices()
private var uniformBuffer: MTLBuffer!
private var lastUpdateDate = Date()
private func setupMetal() {
metalDevice = MTLCreateSystemDefaultDevice() // 1
metalCommandQueue = metalDevice.makeCommandQueue() // 2
metalView.device = metalDevice // 3
metalView.delegate = self // 4
let vertexBufferSize = Vertices.size()
vertexBuffer = metalDevice.makeBuffer(bytes: &Vertices, length: vertexBufferSize, options: .storageModeShared)
let indicesBufferSize = Indices.size()
indicesBuffer = metalDevice.makeBuffer(bytes: &Indices, length: indicesBufferSize, options: .storageModeShared)
let defaultLibrary = metalDevice.makeDefaultLibrary()!
let fragmentProgram = defaultLibrary.makeFunction(name: "basic_fragment")
let vertexProgram = defaultLibrary.makeFunction(name: "basic_vertex") // 1
let pipelineStateDescriptor = MTLRenderPipelineDescriptor()
pipelineStateDescriptor.vertexFunction = vertexProgram
pipelineStateDescriptor.fragmentFunction = fragmentProgram
pipelineStateDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm // 2
pipelineState = try! metalDevice.makeRenderPipelineState(descriptor: pipelineStateDescriptor) // 3
}
override func viewDidLoad() {
super.viewDidLoad()
setupMetal()
}
}
// MARK: - MTKView Delegate Extension
extension ViewController: MTKViewDelegate {
// 1
func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {
let aspect = fabsf(Float(size.width) / Float(size.height)) // 1
let projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0), aspect, 4.0, 10.0) // 2
sceneMatrices.projectionMatrix = projectionMatrix // 3
}
// 2
func draw(in view: MTKView) {
// 1
guard let drawable = view.currentDrawable else {
return
}
let renderPassDescriptor = MTLRenderPassDescriptor() // 2
renderPassDescriptor.colorAttachments[0].texture = drawable.texture // 3
renderPassDescriptor.colorAttachments[0].loadAction = .clear // 4
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(red: 0.85, green: 0.85, blue: 0.85, alpha: 1.0) // 5
// 6
guard let commandBuffer = metalCommandQueue.makeCommandBuffer() else {
return
}
// 7
guard let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) else {
return
}
// Frame drawing goes here
renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0) // 1
// Update logic
var modelViewMatrix = GLKMatrix4MakeTranslation(0.0, 0.0, -6.0)
let timeSinceLastUpdate = lastUpdateDate.timeIntervalSince(Date())
rotation += 90 * Float(timeSinceLastUpdate) // 1
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, GLKMathDegreesToRadians(rotation), 0, 0, 1) // 2
sceneMatrices.modelviewMatrix = modelViewMatrix
// Set uniform buffer
let uniformBufferSize = MemoryLayout.size(ofValue: sceneMatrices)
uniformBuffer = metalDevice.makeBuffer(bytes: &sceneMatrices, length: uniformBufferSize, options: .storageModeShared) // 2
renderEncoder.setVertexBuffer(uniformBuffer, offset: 0, index: 1) // 3
renderEncoder.setRenderPipelineState(pipelineState)
renderEncoder.drawIndexedPrimitives(type: .triangle, indexCount: Indices.count, indexType: .uint32, indexBuffer: indicesBuffer, indexBufferOffset: 0) // 2
renderEncoder.endEncoding() // 8
commandBuffer.addCompletedHandler { _ in
self.lastUpdateDate = Date()
}
commandBuffer.present(drawable) // 9
// 10
}
}
具体效果同OpenGL一样,这里就不展示了。
后记
本篇主要讲述了将项目从OpenGL转化到Metal,感兴趣的给个赞或者关注~~~