Metalを使用して、テクスチャ表示する覚書
「SwiftでMetalを使用して三角形を描画しよう」を参照
https://qiita.com/sanoh/items/98df8d580edaa99c32c9
■Step1:シェーダー変更
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) {
}
}