Metal_入門02_帶你走流程

Metal 系列教程
Metal_入門01_為什么要學習它
Metal_入門02_帶你走流程

  • 有話要說

要學好Metal 它的工作原理,是比較重要的,搞清楚每個類都在干什么事情,就很不錯了,今天只是帶大家跑起來一個工程,熟悉一下相關流程,可能不會用太多的知識點,順便說一句,學過OpenGL 的同學可能理解起來更加容易,但是沒有學過OpenGL 的同學也不要灰心,畢竟兩者沒有任何關系,我們從簡單做起!后面會不斷更新相關技術!

  • 步驟

1.創建工程

讓學習成為一種習慣

就和創建一般的應用工程一樣,我選擇的是Swift 語言,為啥用它,個人比較懶,Swift語法寫起來比較簡單。

2.導入框架

讓學習成為一種習慣

注意

為了簡單,我們借助系統提供給我的Metalkit來簡化操作,后面我會教大家只使用Metal 去實現這個過程,由于是入門就不要那么復雜了。

3.創建Metal專用視圖

let mtkView = MTKView(frame: self.view.bounds)
self.view.addSubview(mtkView)

提示:

這個視圖有個屬性就是MTLDevice 必須要指定的,默認是沒有賦值的

4.獲取GPU設備,檢查手機是否支持

  guard  let device = MTLCreateSystemDefaultDevice() else{
       print("不支持Metal,可以在這里使用OpenGL ES 代替Metal")
       return
 }

提示:

在上一章我們知道,device 代表的就是GPU ,可以創建新的命令隊列,可以分配內存,可以創建紋理和查詢設備信息

5.創建命令線程

let commandQueue = device.makeCommandQueue()

提示:

1.上一章講到過命令線程,主要提供了方法創建命令緩沖對象,MTLCommandBuffer協議為命令緩沖對象定義了一些方法,提供方法去創建命令編碼器,入隊命令緩沖區執行,檢查狀態
2.本實例,我們只用線程隊列創建一個命令緩沖對象

6.創建代表繪圖函數的資源對象

let defaultLibrary = device.newDefaultLibrary()
let fragmentProgram = defaultLibrary?.makeFunction(name: "passThroughFragment")!
let vertexProgram = defaultLibrary?.makeFunction(name: "passThroughVertex")!

提示:

資源對象的作用就是加載Metal 支持的著色器程序,生成MTLFunction 對象,我們在渲染管線描述對象需要使用生成的函數對象
passThroughFragment 和 passThroughVertex 是處理頂點和片段著色器的函數名

讓學習成為一種習慣

7.創建渲染管線描述對象

let pipelineStateDescriptor = MTLRenderPipelineDescriptor()
pipelineStateDescriptor.vertexFunction = vertexProgram// 指定頂點處理程序
pipelineStateDescriptor.fragmentFunction = fragmentProgram// 指定片段程序
pipelineStateDescriptor.colorAttachments[0].pixelFormat = mtkView.colorPixelFormat// 指定顏色格式
pipelineStateDescriptor.sampleCount = mtkView.sampleCount// 設置采樣數量

提示:

這個對象的作用,主要是描述渲染管線狀態的配置信息,如指定片段著色器函數,設置渲染像素格式等
頂點著色器和片段著色器程序方法必須指定,顏色格式也必須設置

8.創建管線狀態對象

 do {
        try pipelineState = device.makeRenderPipelineState(descriptor: pipelineStateDescriptor)
    } catch let error {
        print("Failed to create pipeline state, error \(error)")
    }

提示:

這個對象創建很簡單,就是根據管線描述對象生成需要的管線狀態對象

渲染管線流程圖

8.創建緩沖區(頂點和顏色)

 let vertexLength = vertexData.count * MemoryLayout<Float>.size
 let vertexBuffer = device.makeBuffer(bytes: vertexData, length: vertexLength, options: [])
 let colorLength = vertexColorData.count * MemoryLayout<Float>.size
 let colorBuffer = device.makeBuffer(bytes: vertexColorData, length: colorLength, options: [])

提示:

MTLBuffer 是我們緩存數據的緩沖區對象

10.創建命令緩沖區

let commandBuffer = commandQueue.makeCommandBuffer()

提示:

這個對象相對比較重要,它攜帶了GPU 渲染圖像的所有數據
11.創建命令編碼器

/// 獲取視圖當前的渲染描述和繪制對象
 let renderPassDescriptor = mtkView.currentRenderPassDescriptor
 let currentDrawable = mtkView.currentDrawable // 獲取當前幀的繪制對象
 /// 創建渲染編碼器
 let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor!)
renderEncoder.setRenderPipelineState(pipleState!)// 指定渲染管線對象
 renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, at: 0)// 設置頂點緩沖區
renderEncoder.setVertexBuffer(colorBuffer, offset:0 , at: 1)// 設置顏色緩沖區
renderEncoder.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: 6, instanceCount: 1)// 設置繪制方式
renderEncoder.endEncoding()/// 結束掉這個編碼對象
commandBuffer.present(currentDrawable!) /// 讓繪制對象綁定到當前繪制幀

12.提交

commandBuffer.commit()

提示:

執行這一步,GPU 會記錄命令緩沖區對象,準備渲染

  • 附上頂點和顏色數組
let vertexData:[Float] =
[
    -1.0, -1.0, 0.0, 1.0,
    -1.0,  1.0, 0.0, 1.0,
    1.0, -1.0, 0.0, 1.0,
    
    1.0, 1.0, 0.0, 1.0,
    0.0,  1.0, 0.0, 1.0,
    1.0,  0.0, 0.0, 1.0,
]

let vertexColorData:[Float] =
[
    1.0, 0.0, 0.0, 1.0,
    0.0, 1.0, 0.0, 1.0,
    0.0, 0.0, 1.0, 1.0,
    
    0.0, 0.0, 1.0, 1.0,
    0.0, 1.0, 0.0, 1.0,
    1.0, 0.0, 0.0, 1.0,
]

這個時候你運行一下程序就能看到下面的畫面

讓學習成為一種習慣

我制作了一張流程圖幫助大家理解

不斷的克服困難的任務才有成就感

代碼地址 - 想要不斷學習的同學可以標記一下,后續的代碼都會放在這里

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容