写在前面:
对Metal技术感兴趣的同学,可以关注我的专题:Metal专辑
也可以关注我个人的简书账号:张芳涛
所有的代码存储的Github地址是:Metal
正文
我们来看看使用较新的MetalKit
框架与使用较早的Metal
框架之间有什么区别。 虽然它们仍然共存,但是MetalKit引入了一些强大的功能,例如:
- 容易的
texture
纹理加载(甚至用几行代码进行异步加载)。 -
Model I/O
网格和Metal
缓冲区之间高效的数据传输。 -
MTKView
- 一个方便的Metal-aware
视图(后面会有更详细的介绍)。
我将首先提醒你我们在第一章中看到的程序是什么样的:
import MetalKit
class MetalView: MTKView {
override func drawRect(dirtyRect: NSRect) {
super.drawRect(dirtyRect)
render()
}
func render() {
device = MTLCreateSystemDefaultDevice()
if let rpd = currentRenderPassDescriptor, drawable = currentDrawable {
rpd.colorAttachments[0].clearColor = MTLClearColorMake(0, 0.5, 0.5, 1.0)
let command_buffer = device!.newCommandQueue().commandBuffer()
let command_encoder = command_buffer.renderCommandEncoderWithDescriptor(rpd)
command_encoder.endEncoding()
command_buffer.presentDrawable(drawable)
command_buffer.commit()
}
}
}
就是这样! 简单和优雅的方式来清除你的背景颜色到你选择的自定义颜色。 现在让我们切换到使用没有MTKView
的Metal
框架,所以我们需要改为NSView
(或iOS
中的UIView
)的子类。
import Cocoa
class MetalView: NSView {
您会立即注意到一些错误信号,表明以下属性默认不会再提供给我们:
- a device
- a drawable
- a render pass descriptor
我们来解决这个问题。 首先,由于NSView
不是Metal-aware
,我们需要创建一个CAMetalLayer
并告诉NSView
使用它作为其背景层。 CAMetalLayer
是一个核心动画层,管理用于渲染其内容的纹理池。 要使用Metal
进行渲染,我们需要通过从视图的layerClass()
类方法中返回它,将此类用作视图的背景层。
override class func layerClass() -> AnyClass {
return CAMetalLayer.self
}
var metalLayer: CAMetalLayer {
return self.layer as! CAMetalLayer
}
接下来,在render()
函数中创建一个新设备并告诉metalLayer
它拥有它,并且设置图层将使用的像素格式。 然后,创建一个drawable
。 请注意,我们没有使用随MTKView
一起提供的currentDrawable
。 而是,CAMetalLayer
提供了一个nextDrawable
供我们使用。 最后,创建一个渲染通道描述符。 再次注意,我们没有提供currentRenderPassDescriptor:
let device = MTLCreateSystemDefaultDevice()!
metalLayer.device = device
metalLayer.pixelFormat = .BGRA8Unorm
let drawable = metalLayer.nextDrawable()
let texture = drawable!.texture
let rpd = MTLRenderPassDescriptor()
在本节结束之前,让我们看一下MTKView
类,以再次看到为什么这是使用Metal
在我们的应用中呈现内容的首选方式:
@available(OSX 10.11, *)
public class MTKView : NSView, NSCoding {
public init(frame frameRect: CGRect, device: MTLDevice?)
public init(coder: NSCoder)
weak public var delegate: MTKViewDelegate?
public var device: MTLDevice?
public var currentDrawable: CAMetalDrawable? { get }
public var framebufferOnly: Bool
public var presentsWithTransaction: Bool
public var colorPixelFormat: MTLPixelFormat
public var depthStencilPixelFormat: MTLPixelFormat
public var sampleCount: Int
public var clearColor: MTLClearColor
public var clearDepth: Double
public var clearStencil: UInt32
public var depthStencilTexture: MTLTexture? { get }
public var multisampleColorTexture: MTLTexture? { get }
public func releaseDrawables()
public var currentRenderPassDescriptor: MTLRenderPassDescriptor? { get }
public var preferredFramesPerSecond: Int
public var enableSetNeedsDisplay: Bool
public var autoResizeDrawable: Bool
public var drawableSize: CGSize
public var paused: Bool
public func draw()
}
@available(OSX 10.11, *)
public protocol MTKViewDelegate : NSObjectProtocol {
public func mtkView(view: MTKView,
drawableSizeWillChange size: CGSize)
public func drawInMTKView(view: MTKView)
}
在众多属性中,请注意我们特别感兴趣的属性:device,currentDrawable
和currentRenderPassDescriptor
。 另外值得一提的是,该类为其MTKViewDelegate
属性提供了一个协议。 要详细了解这些属性和功能,请参阅MTKView参考文档。