版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2018.11.01 星期四 |
前言
很多做視頻和圖像的川抡,相信對這個框架都不是很陌生辐真,它渲染高級3D圖形,并使用GPU執(zhí)行數(shù)據(jù)并行計算崖堤。接下來的幾篇我們就詳細(xì)的解析這個框架侍咱。感興趣的看下面幾篇文章。
1. Metal框架詳細(xì)解析(一)—— 基本概覽
2. Metal框架詳細(xì)解析(二) —— 器件和命令(一)
3. Metal框架詳細(xì)解析(三) —— 渲染簡單的2D三角形(一)
4. Metal框架詳細(xì)解析(四) —— 關(guān)于GPU Family 4(一)
5. Metal框架詳細(xì)解析(五) —— 關(guān)于GPU Family 4之關(guān)于Imageblocks(二)
6. Metal框架詳細(xì)解析(六) —— 關(guān)于GPU Family 4之關(guān)于Tile Shading(三)
7. Metal框架詳細(xì)解析(七) —— 關(guān)于GPU Family 4之關(guān)于光柵順序組(四)
8. Metal框架詳細(xì)解析(八) —— 關(guān)于GPU Family 4之關(guān)于增強(qiáng)的MSAA和Imageblock采樣覆蓋控制(五)
9. Metal框架詳細(xì)解析(九) —— 關(guān)于GPU Family 4之關(guān)于線程組共享(六)
10. Metal框架詳細(xì)解析(十) —— 基本組件(一)
11. Metal框架詳細(xì)解析(十一) —— 基本組件之器件選擇 - 圖形渲染的器件選擇(二)
12. Metal框架詳細(xì)解析(十二) —— 基本組件之器件選擇 - 計算處理的設(shè)備選擇(三)
13. Metal框架詳細(xì)解析(十三) —— 計算處理(一)
14. Metal框架詳細(xì)解析(十四) —— 計算處理之你好密幔,計算(二)
15. Metal框架詳細(xì)解析(十五) —— 計算處理之關(guān)于線程和線程組(三)
16. Metal框架詳細(xì)解析(十六) —— 計算處理之計算線程組和網(wǎng)格大行ǜ(四)
17. Metal框架詳細(xì)解析(十七) —— 工具、分析和調(diào)試(一)
18. Metal框架詳細(xì)解析(十八) —— 工具胯甩、分析和調(diào)試之Metal GPU Capture(二)
19. Metal框架詳細(xì)解析(十九) —— 工具昧廷、分析和調(diào)試之GPU活動監(jiān)視器(三)
20. Metal框架詳細(xì)解析(二十) —— 工具、分析和調(diào)試之關(guān)于Metal著色語言文件名擴(kuò)展名偎箫、使用Metal的命令行工具構(gòu)建庫和標(biāo)記Metal對象和命令(四)
21. Metal框架詳細(xì)解析(二十一) —— 基本課程之基本緩沖區(qū)(一)
22. Metal框架詳細(xì)解析(二十二) —— 基本課程之基本紋理(二)
23. Metal框架詳細(xì)解析(二十三) —— 基本課程之CPU和GPU同步(三)
24. Metal框架詳細(xì)解析(二十四) —— 基本課程之參數(shù)緩沖 - 基本參數(shù)緩沖(四)
25. Metal框架詳細(xì)解析(二十五) —— 基本課程之參數(shù)緩沖 - 帶有數(shù)組和資源堆的參數(shù)緩沖區(qū)(五)
26. Metal框架詳細(xì)解析(二十六) —— 基本課程之參數(shù)緩沖 - 具有GPU編碼的參數(shù)緩沖區(qū)(六)
27. Metal框架詳細(xì)解析(二十七) —— 高級技術(shù)之圖層選擇的反射(一)
28. Metal框架詳細(xì)解析(二十八) —— 高級技術(shù)之使用專用函數(shù)的LOD(一)
29. Metal框架詳細(xì)解析(二十九) —— 高級技術(shù)之具有參數(shù)緩沖區(qū)的動態(tài)地形(一)
30. Metal框架詳細(xì)解析(三十) —— 延遲照明(一)
31. Metal框架詳細(xì)解析(三十一) —— 在視圖中混合Metal和OpenGL渲染(一)
32. Metal框架詳細(xì)解析(三十二) —— Metal渲染管道教程(一)
33. Metal框架詳細(xì)解析(三十三) —— Metal渲染管道教程(二)
開始
首先看一下寫作環(huán)境
Swift 4.2, iOS 12, Xcode 10
在iOS 8中木柬,Apple發(fā)布了自己的GPU加速3D圖形API:Metal
。
Metal
類似于OpenGL ES
淹办,因為它是用于與3D圖形硬件交互的較底層API眉枕。
區(qū)別在于Metal不是跨平臺的。相反,它使用Apple硬件設(shè)計得非常高效速挑,與使用OpenGL ES相比谤牡,它提供了更高的速度和更低的開銷。
在本教程中梗摇,您將獲得使用Metal API創(chuàng)建一個簡單的應(yīng)用程序的實踐經(jīng)驗:繪制一個簡單的三角形拓哟。在這樣做的過程中,您將學(xué)習(xí)Metal中一些最重要的類伶授,例如設(shè)備断序,命令隊列等。
本教程的設(shè)計使得任何人都可以看懂它糜烹,無論您的3D圖形背景如何 - 但是违诗,事情會相當(dāng)快地進(jìn)行。如果您確實擁有一些先前的3D編程或OpenGL經(jīng)驗疮蹦,那么您會發(fā)現(xiàn)事情變得更加容易诸迟,因為許多相同的概念適用于Metal。
注意:Metal應(yīng)用程序不能在iOS模擬器上運行愕乎;他們需要帶有
Apple A7
芯片或更高版本的設(shè)備阵苇。要完成本教程,您需要A7 device或更新版本感论。
Metal vs. SpriteKit, SceneKit or Unity
在開始之前绅项,了解Metal如何與SpriteKit
,SceneKit
或Unity
等更高級別的框架進(jìn)行比較會很有幫助比肄。
Metal是一種更接近底層的3D圖形API快耿,類似于OpenGL ES,但開銷較低意味著性能更好芳绩。 它是GPU上方的一個非常薄的層掀亥,這意味著,在執(zhí)行任何操作時妥色,例如將精靈或3D模型渲染到屏幕上搪花,它需要您編寫所有代碼來執(zhí)行此操作。 權(quán)衡是你有充分的能量和控制力嘹害。
相反鳍侣,像SpriteKit
,SceneKit
和Unity
這樣的高級游戲框架是建立在較低級別的3D圖形API(如Metal或OpenGL ES)之上的吼拥。 它們提供了您在游戲中通常需要編寫的大部分樣板代碼倚聚,例如將精靈或3D模型渲染到屏幕上。
如果您要做的就是制作游戲凿可,那么大多數(shù)時候您可能會使用更高級別的游戲框架惑折,如SpriteKit授账,SceneKit或Unity,因為這樣做會讓您的生活更輕松惨驶。
但是白热,學(xué)習(xí)Metal還有兩個很好的理由:
- Push the hardware to its limits - 將硬件推向極限:由于Metal處于如此底層,它可以讓您真正將硬件推向極限并完全控制游戲的工作方式粗卜。
- It’s a great learning experience - 這是一個很好的學(xué)習(xí)經(jīng)歷:Learning Metal教你很多關(guān)于3D圖形屋确,編寫自己的游戲引擎以及更高級別的游戲框架如何工作的知識。
如果其中任何一個聽起來像你的理由续扔,請繼續(xù)閱讀攻臀!
Metal vs. OpenGL ES
OpenGL ES
旨在跨平臺。 這意味著您可以編寫C ++ OpenGL ES
代碼纱昧,并且大多數(shù)情況下刨啸,通過一些小的修改,您可以在其他平臺上運行它识脆,例如Android设联。
Apple意識到,盡管OpenGL ES的跨平臺支持很好灼捂,但它缺少Apple設(shè)計其產(chǎn)品的基本原因:著名的Apple集成了操作系統(tǒng)离例,硬件和軟件作為一個完整的整體。
因此悉稠,Apple采用了一種潔凈室(clean-room)
方法宫蛆,看看它是如何設(shè)計專門針對Apple硬件的圖形API,目標(biāo)是降低開銷和性能偎球,同時支持最新和最強(qiáng)大的功能。
結(jié)果是Metal辑甜,與OpenGL ES相比衰絮,它可以為您的應(yīng)用提供高達(dá)10?
的繪制調(diào)用次數(shù)。 這可能會產(chǎn)生一些驚人的效果 - 您可能會記得在WWDC 2014 keynote中的Zen Garden
示例中作為示例磷醋。
是時候挖掘并查看一些Metal代碼了猫牡!
開始使用Metal渲染需要的七個步驟
Xcode的iOS游戲模板附帶了一個Metal
選項,但你不會在這里選擇邓线。 這是因為你幾乎從頭開始組裝一個Metal應(yīng)用程序淌友,這樣你就可以理解這個過程的每一步。
打開準(zhǔn)備好的工程骇陈,在HelloMetal_starter
文件夾中打開HelloMetal.xcodeproj
震庭。 您將看到一個帶有單個ViewController
的空項目。
設(shè)置Metal需要七個步驟才能開始渲染你雌。 你需要創(chuàng)建一個:
MTLDevice
CAMetalLayer
Vertex Buffer
Vertex Shader
Fragment Shader
Render Pipeline
Command Queue
后面我們會一個個的進(jìn)行有序的講解和說明器联。
1. Creating an MTLDevice - 創(chuàng)建一個MTLDevice
您首先需要獲得對MTLDevice
的引用二汛。
將MTLDevice
視為您與GPU
的直接連接。 您將使用此MTLDevice
創(chuàng)建所需的所有其他Metal對象(如命令隊列拨拓,緩沖區(qū)和紋理)肴颊。
為此,請打開ViewController.swift
并將此導(dǎo)入添加到文件的頂部:
import Metal
這會導(dǎo)入Metal
框架渣磷,以便您可以在此文件中使用諸如MTLDevice
之類的Metal類婿着。
接下來,將此屬性添加到ViewController
:
var device: MTLDevice!
您將在viewDidLoad()
而不是初始化程序中初始化此屬性醋界,因此它必須是可選的竟宋。 由于您知道在使用它之前肯定會對其進(jìn)行初始化,因此為方便起見物独,請將其標(biāo)記為隱式解包的可選項袜硫。
最后,添加viewDidLoad()
并初始化設(shè)備屬性挡篓,如下所示:
override func viewDidLoad() {
super.viewDidLoad()
device = MTLCreateSystemDefaultDevice()
}
MTLCreateSystemDefaultDevice
返回對您的代碼應(yīng)使用的默認(rèn)MTLDevice
的引用婉陷。
2. Creating a CAMetalLayer - 創(chuàng)建一個CAMetalLayer
在iOS中,您在屏幕上看到的所有內(nèi)容都由CALayer
支持官研。 CALayers的子類用于不同的效果秽澳,例如gradient layers, shape layers, replicator layers
等。
如果你想用Metal在屏幕上繪制一些東西戏羽,你需要使用一個名為CAMetalLayer
的特殊CALayer
子類担神。 您將向視圖控制器添加其中一個。
首先始花,將這個新屬性添加到類中:
var metalLayer: CAMetalLayer!
注意:如果此時出現(xiàn)編譯器錯誤妄讯,請確保將應(yīng)用程序Target設(shè)置為針對與Metal兼容的iOS設(shè)備。 如前所述酷宵,
iOS Simulator
目前不支持Metal亥贸。
這將為您的新圖層存儲一個方便的引用。
接下來浇垦,將此代碼添加到viewDidLoad()的末尾:
metalLayer = CAMetalLayer() // 1
metalLayer.device = device // 2
metalLayer.pixelFormat = .bgra8Unorm // 3
metalLayer.framebufferOnly = true // 4
metalLayer.frame = view.layer.frame // 5
view.layer.addSublayer(metalLayer) // 6
下面一步步的進(jìn)行細(xì)分:
- 1) 創(chuàng)建一個新的
CAMetalLayer
炕置。 - 2) 您必須指定圖層應(yīng)使用的
MTLDevice
。 您只需將其設(shè)置為您之前獲得的設(shè)備即可男韧。 - 3) 將像素格式設(shè)置為
bgra8Unorm
朴摊,這是一種奇特的方式,表示“藍(lán)色此虑,綠色甚纲,紅色和Alpha的8個字節(jié),按順序排列 - 標(biāo)準(zhǔn)化值介于0和1之間朦前》犯恚”這是僅有的兩種可用格式之一 一個CAMetalLayer
讹弯,所以通常你只是保持原樣。 - 4) Apple鼓勵您出于性能原因?qū)?code>framebufferOnly設(shè)置為
true
这溅,除非您需要從為此圖層生成的紋理中進(jìn)行采樣组民,或者您需要在圖層可繪制紋理上啟用計算內(nèi)核。 大多數(shù)情況下悲靴,您不需要這樣做臭胜。 - 5) 您可以設(shè)置圖層的frame以匹配視圖的frame。
- 6) 最后癞尚,將圖層添加為視圖主圖層的子圖層耸三。
3. Creating a Vertex Buffer - 創(chuàng)建一個Vertex Buffer
Metal中的一切都是三角形。 在這個應(yīng)用程序中浇揩,您只是繪制一個三角形仪壮,但即使復(fù)雜的3D形狀也可以分解為一系列三角形。
在Metal中胳徽,默認(rèn)坐標(biāo)系是標(biāo)準(zhǔn)化坐標(biāo)系积锅,這意味著默認(rèn)情況下,您正在查看以(0,0,0.5)
為中心的2x2x1
立方體养盗。
如果考慮Z = 0
平面缚陷,則(-1,-1,0)
是左下角往核,(0,0,0)是中心箫爷,(1,1,0)是右上角。 在本教程中聂儒,您希望使用以下三點繪制三角形:
你必須為此創(chuàng)建一個緩沖區(qū)虎锚。 將以下常量屬性添加到您的類:
let vertexData: [Float] = [
0.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0
]
這會在CPU上創(chuàng)建一個浮點數(shù)組。 您需要將此數(shù)據(jù)發(fā)送到GPU衩婚,將其移動到稱為MTLBuffer
的東西窜护。
為此添加另一個新屬性:
var vertexBuffer: MTLBuffer!
然后將此代碼添加到viewDidLoad()
的末尾:
let dataSize = vertexData.count * MemoryLayout.size(ofValue: vertexData[0]) // 1
vertexBuffer = device.makeBuffer(bytes: vertexData, length: dataSize, options: []) // 2
下面一步步的進(jìn)行細(xì)說:
- 1) 您需要以字節(jié)為單位獲取頂點數(shù)據(jù)的大小。 您可以通過將第一個元素的大小乘以數(shù)組中元素的數(shù)量來實現(xiàn)此目的谅猾。
- 2) 您可以在
MTLDevice
上調(diào)用makeBuffer(bytes:length:options :)
在GPU上創(chuàng)建一個新緩沖區(qū)柄慰,從CPU傳入數(shù)據(jù)鳍悠。 您傳遞一個空數(shù)組以進(jìn)行默認(rèn)配置税娜。
4. Creating a Vertex Shader - 創(chuàng)建一個頂點著色器
您在上一節(jié)中創(chuàng)建的頂點將成為您將要編寫的稱為頂點著色器的小程序的輸入。
頂點著色器只是一個在GPU上運行的小程序藏研,用類似C ++的語言編寫敬矩,稱為Metal Shading Language。
頂點著色器每個頂點調(diào)用一次蠢挡,其作用是獲取該頂點的信息弧岳,例如位置 - 以及可能的其他信息凳忙,如顏色或紋理坐標(biāo) - 并返回可能修改的位置和可能的其他數(shù)據(jù)。
為簡單起見禽炬,您的簡單頂點著色器將返回與傳入位置相同的位置涧卵。
理解頂點著色器的最簡單方法是自己查看。 轉(zhuǎn)到File ? New ? File
腹尖,選擇iOS ? Source ? Metal File
柳恐,然后單擊Next
。 輸入Shaders.metal
作為文件名热幔,然后單擊Create
乐设。
注意:在Metal中,您可以在單個Metal文件中包含多個著色器绎巨。 如果您愿意近尚,還可以將著色器分割為多個Metal文件,因為Metal將從項目中包含的任何Metal文件加載著色器场勤。
將以下代碼添加到Shaders.metal
的底部:
vertex float4 basic_vertex( // 1
const device packed_float3* vertex_array [[ buffer(0) ]], // 2
unsigned int vid [[ vertex_id ]]) { // 3
return float4(vertex_array[vid], 1.0); // 4
}
下面進(jìn)行詳細(xì)分解:
- 1) 所有頂點著色器必須以關(guān)鍵字
vertex
開頭戈锻。該函數(shù)必須返回(至少)頂點的最終位置。你可以通過指示float4
(四個浮點數(shù)的向量)來執(zhí)行此操作却嗡。然后給出頂點著色器的名稱舶沛;稍后您將使用此名稱查找著色器。 - 2) 第一個參數(shù)是指向
packed_float3
數(shù)組(三個浮點數(shù)的打包向量)的指針 - 即每個頂點的位置窗价。使用[[...]]
語法聲明屬性如庭,您可以使用這些屬性指定其他信息,例如資源位置撼港,著色器輸入和內(nèi)置變量坪它。在這里,使用[[buffer(0)]]
標(biāo)記此參數(shù)帝牡,以指示從Metal
代碼發(fā)送到頂點著色器的第一個數(shù)據(jù)緩沖區(qū)將填充此參數(shù)往毡。 - 3) 頂點著色器還使用
vertex_id
屬性獲取特殊參數(shù),這意味著Metal將使用頂點數(shù)組內(nèi)此特定頂點的索引填充它靶溜。 - 4) 在這里开瞭,您根據(jù)
vertex id
查找頂點數(shù)組內(nèi)的位置并返回該位置。您還將向量轉(zhuǎn)換為float4
罩息,其中最終值為1.0嗤详,這是3D數(shù)學(xué)所必需的。
5. Creating a Fragment Shader - 創(chuàng)建一個片段著色器
頂點著色器完成后瓷炮,Metal會為屏幕上的每個片段(想象像素)調(diào)用另一個著色器:片段著色器葱色。
片段著色器通過插入頂點著色器的輸出值來獲取其輸入值。 例如娘香,考慮三角形底部兩個頂點之間的片段:
此片段的輸入值將是底部兩個頂點的輸出值的50/50
混合苍狰。
片段著色器的工作是返回每個片段的最終顏色办龄。 為了簡單起見,您將使每個片段變白淋昭。
將以下代碼添加到Shaders.metal
的底部:
fragment half4 basic_fragment() { // 1
return half4(1.0); // 2
}
下面進(jìn)行詳細(xì)分解:
- 1) 所有片段著色器必須以關(guān)鍵字
fragment
開頭俐填。 該函數(shù)必須返回(至少)片段的最終顏色。 你可以通過指示half4
(四分量顏色值RGBA)來實現(xiàn)翔忽。 請注意玷禽,half4
比float4
具有更高的內(nèi)存效率,因為您正在寫入更少的GPU內(nèi)存呀打。 - 2) 在這里矢赁,您返回
(1,1,1,1)
顏色,即白色贬丛。
6. Creating a Render Pipeline - 創(chuàng)建渲染管道
現(xiàn)在您已經(jīng)創(chuàng)建了頂點和片段著色器撩银,您需要將它們與其他一些配置數(shù)據(jù)一起組合到一個稱為渲染管道(render pipeline)
的特殊對象中。
關(guān)于Metal的一個很酷的事情是著色器是預(yù)編譯的豺憔,渲染管道配置是在你第一次設(shè)置之后編譯的额获。 這使一切都非常有效。
首先恭应,向ViewController.swift
添加一個新屬性:
var pipelineState: MTLRenderPipelineState!
這將跟蹤您即將創(chuàng)建的已編譯渲染管道抄邀。
接下來,將以下代碼添加到viewDidLoad()
的末尾:
// 1
let defaultLibrary = device.makeDefaultLibrary()!
let fragmentProgram = defaultLibrary.makeFunction(name: "basic_fragment")
let vertexProgram = defaultLibrary.makeFunction(name: "basic_vertex")
// 2
let pipelineStateDescriptor = MTLRenderPipelineDescriptor()
pipelineStateDescriptor.vertexFunction = vertexProgram
pipelineStateDescriptor.fragmentFunction = fragmentProgram
pipelineStateDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm
// 3
pipelineState = try! device.makeRenderPipelineState(descriptor: pipelineStateDescriptor)
下面進(jìn)行詳細(xì)分解:
- 1) 您可以通過調(diào)用
device.makeDefaultLibrary()
獲得的MTLLibrary
對象訪問項目中包含的任何預(yù)編譯著色器昼榛。 然后境肾,您可以按名稱查找每個著色器。 - 2) 您可以在此處設(shè)置渲染管道配置胆屿。 它包含您要使用的著色器奥喻,以及顏色附件的像素格式 - 即您要渲染的輸出緩沖區(qū),即
CAMetalLayer
本身非迹。 - 3) 最后环鲤,將管道配置編譯為管道狀態(tài),這種狀態(tài)在此處有效使用憎兽。
7. Creating a Command Queue - 創(chuàng)建命令隊列
您需要做的最后一次設(shè)置步驟是創(chuàng)建一個MTLCommandQueue
冷离。
可以將此視為一個有序的命令列表,您可以告訴GPU一次執(zhí)行一個命令纯命。
要創(chuàng)建命令隊列西剥,只需添加一個新屬性:
var commandQueue: MTLCommandQueue!
然后,在viewDidLoad()
的末尾添加以下行:
commandQueue = device.makeCommandQueue()
恭喜 - 您的一次性設(shè)置代碼已完成扎附!
Rendering the Triangle - 渲染三角形
現(xiàn)在蔫耽,是時候轉(zhuǎn)到執(zhí)行每個幀的代碼 - 渲染三角形结耀!
這分五步完成:
- 1)
Create a Display Link
- 2)
Create a Render Pass Descriptor
- 3)
Create a Command Buffer
- 4)
Create a Render Command Encoder
- 5)
Commit your Command Buffer
注意:理論上留夜,這個應(yīng)用程序?qū)嶋H上并不需要每幀渲染一次匙铡,因為三角形在繪制后不會移動。 但是碍粥,大多數(shù)應(yīng)用程序都有移動部分鳖眼,因此您可以通過這種方式來學(xué)習(xí)該過程。 這也為將來的教程提供了一個很好的起點嚼摩。
1. Creating a Display Link - 創(chuàng)建一個Display Link
每次設(shè)備屏幕刷新時钦讳,您都需要一種重繪屏幕的方法。
CADisplayLink
是一個與顯示刷新率同步的計時器枕面。 這項工作的完美工具愿卒! 要使用它,請向該類添加一個新屬性:
var timer: CADisplayLink!
在viewDidLoad()
的末尾初始化它潮秘,如下所示:
timer = CADisplayLink(target: self, selector: #selector(gameloop))
timer.add(to: RunLoop.main, forMode: .default)
這會設(shè)置您的代碼琼开,以便每次屏幕刷新時調(diào)用名為gameloop()
的方法。
最后枕荞,將這些存根方法添加到類中:
func render() {
// TODO
}
@objc func gameloop() {
autoreleasepool {
self.render()
}
}
在這里柜候,gameloop()
只是每幀調(diào)用render()
,現(xiàn)在只有一個空實現(xiàn)躏精。 是時候充實了這一點渣刷。
2. Creating a Render Pass Descriptor - 創(chuàng)建渲染通道描述符
下一步是創(chuàng)建一個MTLRenderPassDescriptor
,它是一個對象矗烛,用于配置要渲染的紋理辅柴,清晰的顏色和其他一些配置。
在render()
中添加這些行代替// TODO
:
guard let drawable = metalLayer?.nextDrawable() else { return }
let renderPassDescriptor = MTLRenderPassDescriptor()
renderPassDescriptor.colorAttachments[0].texture = drawable.texture
renderPassDescriptor.colorAttachments[0].loadAction = .clear
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(
red: 0.0,
green: 104.0/255.0,
blue: 55.0/255.0,
alpha: 1.0)
首先瞭吃,在之前創(chuàng)建的Metal
圖層上調(diào)用nextDrawable()
碌识,它會返回您需要繪制的紋理,以便在屏幕上顯示某些內(nèi)容虱而。
接下來筏餐,配置渲染過程描述符以使用該紋理。 您將加載操作設(shè)置為Clear
牡拇,這意味著“在執(zhí)行任何繪制之前將紋理設(shè)置為clear color
”魁瞪,并將clear color
設(shè)置為要使用的綠色。
3. Creating a Command Buffer - 創(chuàng)建命令緩沖區(qū)
下一步是創(chuàng)建命令緩沖區(qū)惠呼。 將此視為您希望為此幀執(zhí)行的渲染命令列表导俘。 很酷的事情是,在你提交命令緩沖區(qū)之前沒有任何實際發(fā)生剔蹋,讓你對發(fā)生的事情進(jìn)行細(xì)粒度的控制旅薄。
創(chuàng)建命令緩沖區(qū)很簡單。 只需將此行添加到render()
的末尾:
let commandBuffer = commandQueue.makeCommandBuffer()!
命令緩沖區(qū)包含一個或多個渲染命令。 您將創(chuàng)建下一個少梁。
4. Creating a Render Command Encoder - 創(chuàng)建渲染命令編碼器
要創(chuàng)建渲染命令洛口,請使用稱為渲染命令編碼器的輔助對象。 要嘗試這一點凯沪,請將這些行添加到render()
的末尾:
let renderEncoder = commandBuffer
.makeRenderCommandEncoder(descriptor: renderPassDescriptor)!
renderEncoder.setRenderPipelineState(pipelineState)
renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
renderEncoder
.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: 3, instanceCount: 1)
renderEncoder.endEncoding()
在這里第焰,您創(chuàng)建一個命令編碼器并指定您之前創(chuàng)建的管道和頂點緩沖區(qū)。
最重要的部分是對drawPrimitives(type:vertexStart:vertexCount:instanceCount:)
的調(diào)用妨马。 在這里挺举,您告訴GPU基于頂點緩沖區(qū)繪制一組三角形。 為了簡單起見烘跺,你只畫一個湘纵。 方法參數(shù)告訴Metal,每個三角形由三個頂點組成滤淳,從頂點緩沖區(qū)內(nèi)的索引0開始瞻佛,總共有一個三角形。
完成后娇钱,只需調(diào)用endEncoding()
即可伤柄。
5. Committing Your Command Buffer - 提交你的命令緩沖區(qū)
最后一步是提交命令緩沖區(qū)。 將這些行添加到render()的末尾:
commandBuffer.present(drawable)
commandBuffer.commit()
需要第一行來確保GPU在繪圖完成后立即呈現(xiàn)新紋理文搂。 然后提交事務(wù)以將任務(wù)發(fā)送到GPU适刀。
唷煤蹭! 這是一大堆代碼笔喉,但是,最后硝皂,你已經(jīng)完成了常挚! 構(gòu)建并運行應(yīng)用程序,三角形已完成:
另外稽物,請務(wù)必查看Apple的一些優(yōu)秀資源:
- Apple的Metal for Developers頁面奄毡,包含大量文檔,視頻和示例代碼的鏈接
- Apple的Metal Programming Guide
- Apple的Metal Shading Language Guide
- 來自WWDC 2014的Metal視頻
后記
本篇主要講述了一個簡單的三角形的實現(xiàn)贝或,感興趣的給個贊或者關(guān)注~~~~