SwiftでMetalを使用して三角形を描画しよう

Metalを使用して、シェーダーを使った、最小限のサンプル、覚書
■Step1：初期化
---
以前の初期化を参照してください
・iOsでSwiftを使ってMetalを初期化
https://qiita.com/sanoh/items/e54057286adf3d63407b
・MacでSwiftを使ってMetalを初期化
https://qiita.com/sanoh/items/39f26a9a8e519cc61f00
■Setp2：シェーダー作成
---
まず「Shader.metal」を作成します。
![スクリーンショット 2018-11-21 16.09.28.png](https://qiita-image-store.s3.amazonaws.com/0/122121/7b5f1114-c8d5-b13a-2ac9-2738c886c725.png)

```:Shader.metal
#include <metal_stdlib>
using namespace metal;

vertex float4 myVertexShader(const device packed_float3* vertex_array [[ buffer(0) ]],
                             unsigned int vid [[ vertex_id ]]) {
    return float4(vertex_array[vid], 1.0);
}

fragment half4 myFragmentShader() {
    return half4(1.0);
}
```
■Setp3：MetalRenderer.swiftの編集
---
```swift:MetalRenderer.swift
import MetalKit

let maxBuffersInFlight = 3

class MetalRenderer: NSObject, MTKViewDelegate {
    let _device: MTLDevice
    let _command_queue: MTLCommandQueue
    let _in_flight_semaphore = DispatchSemaphore(value: maxBuffersInFlight)
    
    let _buffer_position : MTLBuffer!
    let _render_pipeline_state: MTLRenderPipelineState
    
    init?(metalKitView: MTKView) {
        let vertices_array:[Float] =
            [
                0.0, 1.0, 0.0,
                -1.0, -1.0, 0.0,
                1.0, -1.0, 0.0                
            ]
        _device = metalKitView.device!
        _command_queue = _device.makeCommandQueue()!
        metalKitView.colorPixelFormat = MTLPixelFormat.bgra8Unorm
        //三角形をバッファに登録
        let size = vertices_array.count * MemoryLayout<Float>.size
        _buffer_position = _device.makeBuffer(bytes: vertices_array, length: size)
        //シェーダーを登録
        guard let library = _device.makeDefaultLibrary() else { fatalError() }
        let descriptor = MTLRenderPipelineDescriptor()
        descriptor.vertexFunction=library.makeFunction(name: "myVertexShader")
        descriptor.fragmentFunction=library.makeFunction(name: "myFragmentShader")
        descriptor.colorAttachments[0].pixelFormat = metalKitView.colorPixelFormat
        _render_pipeline_state = try! _device.makeRenderPipelineState(descriptor: descriptor)
        
        super.init()
    }
    
    func draw(in view: MTKView) {
        _ = _in_flight_semaphore.wait(timeout: DispatchTime.distantFuture)
        
        if let command_buffer = _command_queue.makeCommandBuffer() {
            let semaphore = _in_flight_semaphore
            command_buffer.addCompletedHandler { (_ command_buffer)-> Swift.Void in
                semaphore.signal()
            }
            let render_pass_descriptor = view.currentRenderPassDescriptor
            render_pass_descriptor?.colorAttachments[0].loadAction=MTLLoadAction.clear
            render_pass_descriptor?.colorAttachments[0].storeAction=MTLStoreAction.store
            render_pass_descriptor?.colorAttachments[0].clearColor=MTLClearColorMake(1.0, 0.0, 0.0, 1.0)
            if let render_pass_descriptor = render_pass_descriptor {
                if let render_encoder = command_buffer.makeRenderCommandEncoder(descriptor: render_pass_descriptor) {
                    //三角形とシェーダーをキューに登録
                    render_encoder.setRenderPipelineState(_render_pipeline_state)
                    render_encoder.setVertexBuffer(_buffer_position, offset: 0, index: 0)
                    render_encoder.drawPrimitives(type: MTLPrimitiveType.triangle, vertexStart: 0, vertexCount: 3)
                    
                    render_encoder.endEncoding()
                    if let drawable = view.currentDrawable {
                        command_buffer.present(drawable)
                    }
                }
            }
            command_buffer.commit()
        }
    }
    
    func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {
    }
}
```
■Setp4：実行
---
iOsは実機で実行してくださいMacの場合は以下のようになります。
![スクリーンショット 2018-11-21 16.08.22.png](https://qiita-image-store.s3.amazonaws.com/0/122121/ae93e729-4e1d-16fd-12d2-43a499e4b1b7.png)