本系列文章是對 metalkit.org 上面MetalKit內容的全面翻譯和學習.
MetalKit 框架是在 WWDC 2015 上釋出的,它給原Metal框架帶來了大量改進和新特性.認識 MTKView, NSView/UIView
的一個子類. 它內建了一個Metal layer層,也同時管理著幀緩衝器framebuffer及其渲染目標附件render target attachments,還管理著繪製迴圈draw loop.
讓我們建立一個Cocoa Application
(因為iOS
模擬器不支援Metal
).確保只有Swift
和Use Strotyboards
區域是選中狀態.接下來,建立一個新的類,名為MetalView.swift繼承於NSView
(暫時).然後,到storyboard中選中View Controller
下面的View
,設定Identity Inspector
中的類為MetalView
型別,如下圖.
對View Controller
也是同樣操作,刪除Identity Inspector
中Class
下面的View Controller
,因為我們用不到它.刪除ViewController.swift
因為我也不需要它了.現在回到MetalView.swift
檔案中,輸入import MetalKit.有兩種方法可以讓我們的類支援繪製:遵守MTKViewDelegate
協議並實現它的drawInView(:)
方法,或者繼承MTKView
並重寫它的drawRect(:)
方法.這裡我們選擇後者,所以將類的型別從NSView
改為MTKView,並建立一個新方法名為render()
,內容如下:
func render() {
let device = MTLCreateSystemDefaultDevice()!
self.device = device
let rpd = MTLRenderPassDescriptor()
let bleen = MTLClearColor(red: 0, green: 0.5, blue: 0.5, alpha: 1)
rpd.colorAttachments[0].texture = currentDrawable!.texture
rpd.colorAttachments[0].clearColor = bleen
rpd.colorAttachments[0].loadAction = .Clear
let commandQueue = device.newCommandQueue()
let commandBuffer = commandQueue.commandBuffer()
let encoder = commandBuffer.renderCommandEncoderWithDescriptor(rpd)
encoder.endEncoding()
commandBuffer.presentDrawable(currentDrawable!)
commandBuffer.commit()
}
複製程式碼
讓我們一行一行來細看這些程式碼.首先,我們建立一個device.我們將其設定為我們view的屬性device
,否則該屬性為nil
程式會崩潰.作為一個可選項,我們可以在繪製之前修改view的drawable
屬性.接著,建立一個render pass descriptor(渲染通道描述符) 以便我們配置渲染通道為current drawable’s texture
附著上初始顏色.為了有趣一點,我們建立一個很棒的顏色,由一半藍色一半綠色組成,叫bleen.最後,我們使用命令緩衝器來建立render command encoder來執行繪製命令.對於每個繪製迴圈,當currentRenderPassDescriptor
查詢時,建立一個新的MTLRenderPassDescriptor
物件.這個物件是基於currentDrawable
物件建立的.畫面顯示並不是MTKView
處理的,所以我們必須自己先檢查currentRenderPassDescriptor
和currentDrawable
都為為nil
,然後再呼叫presentDrawable(:)
方法.
讓我們參考一下Metal 文件中的細節.Metal
框架包含若干物件:
device裝置
-對GPU
的抽象,處理命令佇列中的渲染和計算命令command queue命令佇列
-一個命令緩衝器的序列佇列,確保儲存的命令按順序執行command buffer命令緩衝器
-儲存從命令編碼器中編譯出的指令.當能問執行完所有命令後Metal會通知應用程式.command encoder命令編碼器
-將API
命令編譯成GPU
硬體命令-共有三種型別的編碼器:render
(供圖形渲染),compute
(供資料並行處理)及blit
(供資源複製操作).目前我們只需關注render command encoder渲染命令編碼器
states狀態
-例如混合和深度shaders著色器
-原始碼resources資源
-紋理和資料緩衝器
我們在本系列的下一節中將討論最後3個物件.當前我們只關注device
,queue
,buffer
和encoder
.Render Command Encoder (RCE)渲染命令編碼器
為每一個單獨的渲染通道提供硬體命令,這意味著所有的渲染都被送入一個單一的framebuffer幀緩衝器
物件中(目標集合中).如果另一個幀緩衝器需要被渲染,會建立一個新的RCE.RCE會為從graphics popeline圖形管線
中給出的vertex頂點
和fragment片段
確定狀態,並且插入resources
,state changes
和draw calls
.利用RCE
的一個優點是無需繪製時編譯;應用可以決定編譯和狀態檢查何時發生,這樣為程式設計師提供了很大的效能優勢.
讓我們再回到我們的程式碼.在drawRect(:) 方法中呼叫render()
方法:
override func drawRect(dirtyRect: NSRect) {
super.drawRect(dirtyRect)
render()
}
複製程式碼
如果你執行應用,你將會看到一個漂亮的,純粹的bleen-ish
螢幕:
在下一節中,我們終於開始介紹shaders
,載入textures
及管理model data模型資料
.程式碼 source code 釋出於Github
上.
下次見!