Metal學習筆記

關於Metal® Programming Guide Tutorial and Reference via Swift-中文.pdf的學習日誌

第一部分:Metal Basics

import UIKit
import Metal //導入Metal
import QuartzCore //創建Core Animation層

class ViewController: UIViewController {

 //1: 創建MTL設備
    var device:MTLDevice! = nil
 //2:創建CAMetalLayer
    var metalLayer:CAMetalLayer?
 //3:創建一個頂點緩衝區
    var vertexBuffer: MTLBuffer! = nil
  //4:需要設置一個對象來保存渲染管道需要引用的所有狀態
    var pipelineState: MTLRenderPipelineState! = nil
  //5:命令隊列是負責通過GPU完成工作來調度時間的對象
     var commandQueue: MTLCommandQueue! = nil
//6:需要視圖控制器類才能知道它需要刷新屏幕。這是使用CADisplayLink完成的
    var timer: CADisplayLink! = nil

    override func viewDidLoad() {
        super.viewDidLoad()
       //1: 創建MTL設備
        device = MTLCreateSystemDefaultDevice()
       //2:創建CAMetalLayer
        metalLayer = CAMetalLayer()
        metalLayer?.device = device
        metalLayer?.pixelFormat = .bgra8Unorm
        metalLayer?.framebufferOnly = true
        metalLayer?.frame = view.layer.frame
        view.layer.addSublayer(metalLayer!)
        //三角形座標數據
        let vertexData:[Float] = [ 0.0, 0.5, 0.0,
                                   -0.5, -0.5, 0.0,
                                   0.5, -0.5, 0.0]
        //3:創建一個頂點緩衝區
        let dataSize = vertexData.count * MemoryLayout.size(ofValue: vertexData[0])
        vertexBuffer = device.makeBuffer(bytes: vertexData,length:dataSize,options: [])

        // Set the Rendering Pipeline
      //需要創建一個庫來保存着色器程序Shaders.metal
        let defaultLibrary = device.makeDefaultLibrary()
        let fragmentProgram = defaultLibrary?.makeFunction(name: "basic_fragment")
        let vertexProgram = defaultLibrary?.makeFunction(name: "basic_vertex")

      //4:需要設置一個對象來保存渲染管道需要引用的所有狀態
        let pipelineStateDescriptor = MTLRenderPipelineDescriptor()
        pipelineStateDescriptor.vertexFunction = vertexProgram
        pipelineStateDescriptor.fragmentFunction = fragmentProgram
        pipelineStateDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm
        do {
            try pipelineState = device.makeRenderPipelineState(descriptor:pipelineStateDescriptor)
        }catch let error {
            print("Failed to create pipeline state, error \(error)") }

      //5:命令隊列是負責通過GPU完成工作來調度時間的對象,命令隊列是一個昂貴的對象,因此您只想創建一個並重用它
        commandQueue = device.makeCommandQueue()

        timer = CADisplayLink(target:self,selector:#selector(ViewController.gameloop))
        timer.add(to:RunLoop.main,forMode:RunLoop.Mode.default)
    }

  //設置渲染過程
    func render() {
        let renderPassDescriptor = MTLRenderPassDescriptor()
        guard let drawable = metalLayer?.nextDrawable() else {return}
        renderPassDescriptor.colorAttachments[0].texture = drawable.texture
        renderPassDescriptor.colorAttachments[0].loadAction = .clear
        renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(red:
            221.0/255.0, green: 160.0/255.0, blue: 221.0/255.0, alpha: 1.0)

      //命令隊列不直接採用渲染過程。相反,它需要命令緩衝區對象
          let commandBuffer = commandQueue.makeCommandBuffer()
      //命令緩衝區需要編碼渲染命令
        let renderEncoder = commandBuffer?.makeRenderCommandEncoder(descriptor:renderPassDescriptor)
        renderEncoder?.setRenderPipelineState(pipelineState)
        renderEncoder?.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
        renderEncoder?.drawPrimitives(type: .triangle,vertexStart: 0,vertexCount: 3)
        renderEncoder?.endEncoding()
        commandBuffer?.present(drawable)
        commandBuffer?.commit()
    }

    @objc func gameloop() { autoreleasepool { self.render()} }




}

創建一個新文件。從模板選項中選擇Metal,並將新文件命名爲Shaders.metal。確保將文件保存到項目目錄中。

//兩種着色器類型都是用金屬着色語言(MSL)編寫的,它基於C ++ 14

#include <metal_stdlib>
using namespace metal;
//創建頂點着色器,所有頂點着色器必須以關鍵字vertex開頭。它們還必須至少以float4對象的形式返回頂點的位置數據。
vertex float4 basic_vertex(const device packed_float3* vertex_array [[ buffer(0) ]], unsigned int vid [[ vertex_id ]]) {
    return float4(vertex_array[vid], 1.0);
}
//創建片段着色器,片段着色器負責計算屏幕上每個像素的顏色
fragment half4 basic_fragment(){
    return half4(1.0);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章