LoginSignup
2
1

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-11-21

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

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の編集

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

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1