Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

Metalを使用して、テクスチャ表示する覚書
「SwiftでMetalを使用して三角形を描画しよう」を参照
https://qiita.com/sanoh/items/98df8d580edaa99c32c9

■Step1:シェーダー変更

まずはShaderType.h を追加します。
スクリーンショット 2018-11-30 14.22.14.png

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を編集します。

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
「Texture」が作成されます。
スクリーンショット 2018-11-30 14.22.45.png
今回用意したテクスチャ(Pngファイル)
color.png
テクスチャを「All Universel」にドラッグ&ドロップし名前を「colorImage」に変更します。
スクリーンショット 2018-11-30 14.23.08.png

■Setp4:実行

iOsは実機で実行してくださいMacの場合は以下のようになります。
スクリーンショット 2018-11-30 12.30.01.png

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away