Metal框架詳細(xì)解析(三十四) —— Hello Metal! 一個簡單的三角形的實現(xiàn)(一)

版本記錄

版本號 時間
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如何與SpriteKitSceneKitUnity等更高級別的框架進(jìn)行比較會很有幫助比肄。

Metal是一種更接近底層的3D圖形API快耿,類似于OpenGL ES,但開銷較低意味著性能更好芳绩。 它是GPU上方的一個非常薄的層掀亥,這意味著,在執(zhí)行任何操作時妥色,例如將精靈或3D模型渲染到屏幕上搪花,它需要您編寫所有代碼來執(zhí)行此操作。 權(quán)衡是你有充分的能量和控制力嘹害。

相反鳍侣,像SpriteKitSceneKitUnity這樣的高級游戲框架是建立在較低級別的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)翔忽。 請注意玷禽,half4float4具有更高的內(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)秀資源:

后記

本篇主要講述了一個簡單的三角形的實現(xiàn)贝或,感興趣的給個贊或者關(guān)注~~~~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末吼过,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖展箱,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異趟佃,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進(jìn)店門闲昭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來罐寨,“玉大人,你說我怎么就攤上這事汤纸。” “怎么了芹血?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵贮泞,是天一觀的道長。 經(jīng)常有香客問我幔烛,道長啃擦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任饿悬,我火速辦了婚禮令蛉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘狡恬。我一直安慰自己珠叔,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布弟劲。 她就那樣靜靜地躺著祷安,像睡著了一般。 火紅的嫁衣襯著肌膚如雪兔乞。 梳的紋絲不亂的頭發(fā)上汇鞭,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天,我揣著相機(jī)與錄音庸追,去河邊找鬼霍骄。 笑死,一個胖子當(dāng)著我的面吹牛淡溯,可吹牛的內(nèi)容都是我干的读整。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼咱娶,長吁一口氣:“原來是場噩夢啊……” “哼绘沉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起豺总,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤车伞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后喻喳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體另玖,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了谦去。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片慷丽。...
    茶點故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖鳄哭,靈堂內(nèi)的尸體忽然破棺而出要糊,到底是詐尸還是另有隱情,我是刑警寧澤妆丘,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布锄俄,位于F島的核電站,受9級特大地震影響勺拣,放射性物質(zhì)發(fā)生泄漏奶赠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一药有、第九天 我趴在偏房一處隱蔽的房頂上張望毅戈。 院中可真熱鬧,春花似錦愤惰、人聲如沸苇经。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽塑陵。三九已至,卻和暖如春蜡励,著一層夾襖步出監(jiān)牢的瞬間令花,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工凉倚, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留兼都,地道東北人。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓稽寒,卻偏偏與公主長得像扮碧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子杏糙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,543評論 2 349

推薦閱讀更多精彩內(nèi)容