import UIKit
import MetalKit
class ViewController: UIViewController {
// // 保证render与metalView使用的是同一个MTLDevice
let device = MTLCreateSystemDefaultDevice()
lazy var metalView: MTKView = {
let view = MTKView(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
// 控制是否只在需要更新内容时才重新绘制, 默认false,每一帧都重新绘制
view.enableSetNeedsDisplay = true
// 设置MTLDevice
view.device = device
// 清屏颜色(参照OpenGL)
view.clearColor = MTLClearColor(red: 0.0, green: 0.0, blue: 1.0, alpha: 1.0)
// MTKView的渲染控制必须要有一个符合MTKViewDelegate的代理实现
view.delegate = self.render
return view
}()
lazy var render: MetalRender = {
// 传入MTLDevice,来生成命令队列
let render = MetalRender(device)
return render
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(metalView)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
metalView.frame = CGRect(x: 100, y: 100, width: 200, height: 200)
}
}
view.enableSetNeedsDisplay = true合理的使用这个,可以提高性能。
import UIKit
import MetalKit
class MetalRender: NSObject {
var commandQueue: MTLCommandQueue?
private override init() {
super.init()
}
convenience init(_ device: MTLDevice?) {
self.init()
// 生成命令队列
self.commandQueue = device?.makeCommandQueue()
}
}
extension MetalRender: MTKViewDelegate {
// MTKViewDelegate必须实现的方法
func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {
// 每当视图改变方向或调整大小时调用
print("mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize)")
}
// MTKViewDelegate必须实现的方法
func draw(in view: MTKView) {
// 绘制内容
print("draw(in view: MTKView)")
// 必须获取到MTLRenderPassDescriptor才行
// MTLRenderPassDescriptor描述了呈现目标的集合,以及在呈现通道的开始和结束时应该如何处理它们。
// MTLRenderPassDescriptor还定义了渲染的其他方面,这些方面不属于本示例的一部分。
guard let renderPassDescriptor = view.currentRenderPassDescriptor else {
print("view.currentRenderPassDescriptor == nil")
return
}
let commandBuffer = commandQueue?.makeCommandBuffer()
let commandEncoder = commandBuffer?.makeRenderCommandEncoder(descriptor: renderPassDescriptor)
// 这个示例中,没有编码任何绘制命令,所以渲染通道所做的唯一事情就是擦除纹理。调用编码器的endEncoding方法以指示传递完成。
commandEncoder?.endEncoding()
// 绘制纹理不会自动在屏幕上显示新的内容。事实上,只有一些纹理可以呈现在屏幕上。
// 在Metal中,可以在屏幕上显示的纹理是由可绘制对象MTLDrawable管理的,为了显示内容,您可以呈现可绘制对象。
// MTKView自动创建可绘制的对象来管理它的纹理。读取currentDrawable属性以获取drawable对象,该对象拥有渲染通道的目标纹理。
// 视图返回一个CAMetalDrawable对象,一个连接到Core Animation的对象。
if let drawable = view.currentDrawable {
// 这个方法告诉Metal,当命令缓冲区被调度执行时,Metal应该与Core Animation协调,在渲染完成后显示纹理。
// 当Core Animation呈现纹理时,它成为视图的新内容。
// 在这个示例中,这意味着擦除的纹理成为视图的新背景。
// 这一变化与Core Animation为屏幕用户界面元素所做的任何其他视觉更新一起发生。
commandBuffer?.present(drawable)
}
// 提交命令缓冲区
commandBuffer?.commit()
}
}
运行输出:
draw(in view: MTKView)
点击后输出:
mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize)