本系列文章是對 metalkit.org 上面MetalKit內容的全面翻譯和學習.
讓我們來看看新的MetalKit
框架和以前的Metal
框架有什麼不同.它們是同時共存的,但是,MetalKit
引入了一些強勁的新特性,比如:
紋理
更容易載入(只需幾行程式碼就可以非同步載入).Model I/O
網格mash和Metal
緩衝器buffer之間的高效資料傳輸.MTKView
-一個方便的Metal-aware Metal認識的
檢視(我們稍後會深入研究它).
我將從回顧第一篇中的程式開始:
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()
}
}
}
複製程式碼
就是這樣!簡單優雅清理裝置的背景色.現在我們切換到Metal
框架,它並沒有MTKView
,所以我們必須繼承於NSView
(iOS
上是UIView
).
import Cocoa
class MetalView: NSView {
複製程式碼
你會直接注意到一些錯誤提示,顯示下面的屬性預設情況下沒有提供給我們:
- a device裝置
- a drawable繪製資源
- a render pass descriptor渲染通道描述符
讓我們修復這些錯誤.首先,因為NSView
不是Metal-aware Metal認識的
,我們需要建立一個CAMetalLayer
並告訴NSView
將其用做自己的支援層.CAMetalLayer
是Core Animation
層,它管理著一個用來渲染內容的紋理池.為了使用Metal
來渲染,我們需要用這個類作為我們檢視的支援層,通過在檢視的layerClass() 類方法中返回圖層來實現:
override class func layerClass() -> AnyClass {
return CAMetalLayer.self
}
var metalLayer: CAMetalLayer {
return self.layer as! CAMetalLayer
}
複製程式碼
接下來,在render() 函式中建立一個新的device
並告訴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類,去看看為什麼這是在我們的app中用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的參考文件.
原始碼source code 已釋出在Github上.
下次見!