SwiftでMetalを使用してテクスチャを表示しよう

Metalを使用して、テクスチャ表示する覚書
「SwiftでMetalを使用して三角形を描画しよう」を参照
https://qiita.com/sanoh/items/98df8d580edaa99c32c9
■Step1：シェーダー変更
---
まずはShaderType.h を追加します。
![スクリーンショット 2018-11-30 14.22.14.png](https://qiita-image-store.s3.amazonaws.com/0/122121/7c4e3913-cb2e-ec88-8803-fc9995e2bd3e.png)

```c:ShaderType.h
#ifndef ShaderType_h
#define ShaderType_h

#ifdef __METAL_VERSION__
#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
#define NSInteger metal::int32_t
#else
#import <Foundation/Foundation.h>
#endif

#include <simd/simd.h>

typedef NS_ENUM(NSInteger, BufferIndex)
{
    BufferIndexMeshPositions = 0
};

typedef NS_ENUM(NSInteger, TextureIndex)
{
    TextureIndexColor    = 0,
};

#endif /* ShaderType_h */
```
Shader.Metal を編集

```:Shader.Metal
#include <metal_stdlib>
#include <simd/simd.h>
#import "ShaderType.h"

using namespace metal;

struct Vertex {
    float2 position;
    float2 texCoord;
};

struct ColorInOut{
    float4  position [[position]];
    float2  texCoord;
};

vertex ColorInOut myVertexShader(constant Vertex *vertices [[buffer(BufferIndexMeshPositions)]],
                                 uint vid [[vertex_id]]) {
    ColorInOut  out;

    out.position    = float4(vertices[vid].position, 0.0, 1.0);
    out.texCoord    = vertices[vid].texCoord;
    return out;
}

fragment half4 myFragmentShader(ColorInOut vert [[stage_in]],
                                texture2d<half> colorMap     [[ texture(TextureIndexColor) ]]) {
    constexpr sampler defaultSampler;
    half4 imageColor = colorMap.sample(defaultSampler, vert.texCoord.xy);
    return imageColor;
}
```
■Steop2: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

    let _color_image: MTLTexture	//＜新規＞

    init?(metalKitView: MTKView) {
        //頂点データ＜更新＞
        let vertices_array:[Float] =
            [
                +0.0, +1.0, 0.0, 0.0,
                -1.0, -1.0, 1.0, 0.0,
                +1.0, -1.0, 1.0, 1.0,
            ]
        _device = metalKitView.device!
        metalKitView.colorPixelFormat = MTLPixelFormat.bgra8Unorm
        _command_queue = _device.makeCommandQueue()!
        //  頂点情報の登録
        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)
        //  テクスチャ読込+登録＜新規＞
        let textureLoader = MTKTextureLoader(device: _device)
        let textureLoaderOptions = [
            MTKTextureLoader.Option.textureUsage: NSNumber(value: MTLTextureUsage.shaderRead.rawValue),
            MTKTextureLoader.Option.textureStorageMode: NSNumber(value: MTLStorageMode.`private`.rawValue)
        ]
        _color_image    = try! textureLoader.newTexture(name: "colorImage",
                                                       scaleFactor: 1.0,
                                                       bundle: nil,
                                                       options: textureLoaderOptions)
        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.setFragmentTexture(_color_image,
                                                      index: TextureIndex.color.rawValue)
                    //  モデルの設定
                    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) {
    }
}
```
■Steop3:テクスチャをアセットに登録
---
「Assets.xcassets」に右クリックでメニューを出し「New Texture Set」を選択します。
![スクリーンショット 2018-11-30 14.22.35.png](https://qiita-image-store.s3.amazonaws.com/0/122121/d5cb5593-ed78-9c82-12af-263c0a8b00b4.png)
「Texture」が作成されます。
![スクリーンショット 2018-11-30 14.22.45.png](https://qiita-image-store.s3.amazonaws.com/0/122121/1d93b616-daa5-d2a5-45ef-2593e9c91694.png)
今回用意したテクスチャ（Pngファイル）
![color.png](https://qiita-image-store.s3.amazonaws.com/0/122121/2360c97d-f9e9-b93d-ebe8-4fdb626fc973.png)
テクスチャを「All Universel」にドラッグ＆ドロップし名前を「colorImage」に変更します。
![スクリーンショット 2018-11-30 14.23.08.png](https://qiita-image-store.s3.amazonaws.com/0/122121/3cfa17b3-cbea-be16-68d2-5e9f14a24353.png)
■Setp4：実行
---
iOsは実機で実行してくださいMacの場合は以下のようになります。
![スクリーンショット 2018-11-30 12.30.01.png](https://qiita-image-store.s3.amazonaws.com/0/122121/5bd808dc-7d77-58fc-72f6-7e3b557fafa9.png)