Metalを使用して、テクスチャ表示する覚書
「Objective-cでMetalを使用して三角形を描画しよう」を参照
https://qiita.com/sanoh/items/cfc7ecb057b7588c2a52
■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.mを編集します。
MetalRenderer.m
#import "MetalRenderer.h"
#import "ShaderType.h"
static const NSUInteger MaxBuffersInFlight = 3;
@implementation MetalRenderer
{
dispatch_semaphore_t _in_flight_semaphore;
id <MTLDevice> _device;
id <MTLCommandQueue> _command_queue;
id <MTLRenderPipelineState> _pipeline_state;
id <MTLBuffer> _buffer_position;
id <MTLTexture> _color_image; //<新規>
}
-(nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)view;
{
//頂点情報<変更>
float vertices_array[]={
+0.0, +1.0, 0.0, 0.0,
-1.0, -1.0, 1.0, 0.0,
+1.0, -1.0, 1.0, 1.0,
};
if(self= [super init])
{
_device = view.device;
_in_flight_semaphore = dispatch_semaphore_create(MaxBuffersInFlight);
_command_queue = [_device newCommandQueue];
view.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
// 頂点情報の登録
NSInteger size = sizeof(vertices_array);
_buffer_position=[_device newBufferWithBytes:vertices_array
length:size
options:MTLResourceOptionCPUCacheModeDefault];
// シェーダーの登録
id <MTLLibrary> library = [_device newDefaultLibrary];
MTLRenderPipelineDescriptor *descriptor = [[MTLRenderPipelineDescriptor alloc] init];
descriptor.vertexFunction = [library newFunctionWithName:@"myVertexShader"];
descriptor.fragmentFunction = [library newFunctionWithName:@"myFragmentShader"];
descriptor.colorAttachments[0].pixelFormat=MTLPixelFormatBGRA8Unorm;
NSError *error = NULL;
_pipeline_state = [_device newRenderPipelineStateWithDescriptor:descriptor
error:&error];
if (!_pipeline_state)
{
NSLog(@"Failed to created pipeline state, error %@", error);
}
// テクスチャ読込+登録<新規>
MTKTextureLoader* textureLoader = [[MTKTextureLoader alloc] initWithDevice:_device];
NSDictionary *textureLoaderOptions =
@{
MTKTextureLoaderOptionTextureUsage : @(MTLTextureUsageShaderRead),
MTKTextureLoaderOptionTextureStorageMode : @(MTLStorageModePrivate)
};
_color_image = [textureLoader newTextureWithName:@"colorImage"
scaleFactor:1.0
bundle:nil
options:textureLoaderOptions
error:&error];
if(!_color_image || error)
{
NSLog(@"Error creating texture %@", error.localizedDescription);
}
}
return self;
}
- (void)drawInMTKView:(nonnull MTKView *)view
{
dispatch_semaphore_wait(_in_flight_semaphore, DISPATCH_TIME_FOREVER);
id <MTLCommandBuffer> command_buffer = [_command_queue commandBuffer];
__block dispatch_semaphore_t block_sema = _in_flight_semaphore;
[command_buffer addCompletedHandler:^(id<MTLCommandBuffer> buffer)
{
dispatch_semaphore_signal(block_sema);
}];
MTLRenderPassDescriptor* render_pass_descriptor = view.currentRenderPassDescriptor;
render_pass_descriptor.colorAttachments[0].loadAction=MTLLoadActionClear;
render_pass_descriptor.colorAttachments[0].storeAction=MTLStoreActionStore;
render_pass_descriptor.colorAttachments[0].clearColor=MTLClearColorMake(1.0, 0.0, 0.0, 1.0);
if(render_pass_descriptor != nil)
{
id <MTLRenderCommandEncoder> render_encoder = [command_buffer renderCommandEncoderWithDescriptor:render_pass_descriptor];
// テクスチャの設定
[render_encoder setFragmentTexture:_color_image
atIndex:TextureIndexColor];
// モデルの設定
[render_encoder setRenderPipelineState:_pipeline_state];
[render_encoder setVertexBuffer:_buffer_position
offset:0
atIndex:BufferIndexMeshPositions];
[render_encoder drawPrimitives:MTLPrimitiveTypeTriangle
vertexStart:0
vertexCount:3];
[render_encoder endEncoding];
[command_buffer presentDrawable:view.currentDrawable];
}
[command_buffer commit];
}
- (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size
{
}
@end
■Steop3:テクスチャをアセットに登録
「Assets.xcassets」に右クリックでメニューを出し「New Texture Set」を選択します。
「Texture」が作成されます。
今回用意したテクスチャ(Pngファイル)
テクスチャを「All Universel」にドラッグ&ドロップし名前を「colorImage」に変更します。