项目准备
新建一个iOS项目,值得注意的是:life Cycle请选择 UIKit App Delegate,后续因为需要从UIView中集成,项目还需要做一些变化。
删除 AppDelegate.swift中关于SceneDeleagete的相关函数,添加一个成员变量window类型为UIWindow。删除info.plist中关于Scene Manifest的配置,添加一个storyboard。命名为main.storyboard,添加一个View Control,设置这个View Control为 “is initial view control”。(尝试拖一个label到view中,运行程序后,查看结果)
Hello Metal
- 添加MyViewController.swift创建 MyViewController 类继承自 UIViewController
- 添加参数metalView作为MTKView的持有,并且初始化。
- 在main.storyboard中分别对viewcontroler和内部的view设置Class,分别为MyViewController,MTKView。MyViewController的代码如下:
import UIKit
import MetalKit
class MyViewController:UIViewController{
var metalView:MTKView{
return view as! MTKView
}
override func viewDidLoad() {
}
}
初始化Metal
添加以下代码。运行后,Metal会绘制背景颜色,此时,metal只会在运行的时候去绘制一次,并不能在在一定的从刷新率下去重绘。
enum Colors {
static let wenderlichGreen = MTLClearColor(red:0.0,green: 0.4,blue: 0.21,alpha: 1.0)
}
override func viewDidLoad() {
super.viewDidLoad()
metalView.device = MTLCreateSystemDefaultDevice()// 创建设备
device = metalView.device //设置到controller的成员变量中
metalView.clearColor = Colors.wenderlichGreen //设置背景颜色
commandQueue = device.makeCommandQueue() //为gpu准备指令队列
let commandBuffer = commandQueue.makeCommandBuffer() //为指令队列设置缓冲区
let commandEncoder = commandBuffer?.makeRenderCommandEncoder(descriptor: metalView.currentRenderPassDescriptor!) //为缓冲区创建一个编码器
commandEncoder?.endEncoding()//停止编码
commandBuffer?.present(metalView.currentDrawable as! MTLDrawable) //绘制图像
commandBuffer?.commit() //提交给gpu
}
初始化
- 首先Metal需要创建一个设备,这个设备可以理解成GPU
- GPU需要接受一系列指令,因此我们需要创建一个CommandQueue
- 设置一些PiplineState,这些State可以告诉GPU需要执行哪些渲染函数。
- 当然,GPU也需要MTLBuffer来存储一些Model和Texture。例如,需要渲染一个三角形的时候,我们需要把定点的位置记在MTLBuffer里面
渲染时
- 需要创建一个CommandBuffer,这里存储了如何渲染的信息
- CommandBuffer需要创建一个Encoder,Encoder需要找到相关的渲染素材,比如Model和Texture。
- 最后需要使用Commit,提交给GPU
实现每帧刷新
- controler继承MTKViewDelegate,因此需要实现两个函数,一个是mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize),另外一个是func draw(in view: MTKView) 。
- 把MetalView的delegate设置为controler
整体的代码如下:
import UIKit
import MetalKit
enum Colors {
static let wenderlichGreen = MTLClearColor(red:0.0,green: 0.4,blue: 0.21,alpha: 1.0)
}
class MyViewController:UIViewController,MTKViewDelegate{
var metalView:MTKView{
return view as! MTKView
}
var device:MTLDevice!
var commandQueue:MTLCommandQueue!
override func viewDidLoad() {
super.viewDidLoad()
metalView.device = MTLCreateSystemDefaultDevice()// 创建设备
device = metalView.device //设置到controller的成员变量中
metalView.clearColor = Colors.wenderlichGreen //设置背景颜色
commandQueue = device.makeCommandQueue() //为gpu准备指令队列
metalView.delegate = self
}
func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {
}
func draw(in view: MTKView) {
let commandBuffer = commandQueue.makeCommandBuffer() //为指令队列设置缓冲区
let commandEncoder = commandBuffer?.makeRenderCommandEncoder(descriptor: metalView.currentRenderPassDescriptor!) //为缓冲区创建一个编码器
commandEncoder?.endEncoding()//停止编码
commandBuffer?.present(metalView.currentDrawable as! MTLDrawable) //绘制图像
commandBuffer?.commit() //提交给gpu
}
}