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)
{
BufferIndexPositions = 0,
BufferIndexUniforms = 1
};
typedef struct
{
float color[3];
} Uniforms;
#endif /* ShaderType_h */
Shader.Metal を編集
Shader.metal
#include <metal_stdlib>
#import "ShaderType.h"
using namespace metal;
vertex float4 myVertexShader(const device packed_float3* vertex_array [[ buffer(BufferIndexPositions) ]],
unsigned int vid [[ vertex_id ]]) {
return float4(vertex_array[vid], 1.0);
}
fragment half4 myFragmentShader(constant Uniforms & uniforms [[ buffer(BufferIndexUniforms) ]]) {
return half4(uniforms.color[0], uniforms.color[1], uniforms.color[2] , 1.0);
}
■Steop2:MetalRenderer.mを編集します。
MetalRenderer.m
#import "MetalRenderer.h"
#import "ShaderType.h"
static const NSUInteger MaxBuffersInFlight = 3;
static const size_t kAlignedUniformsSize = (sizeof(Uniforms) & ~0xFF) + 0x100;
@implementation MetalRenderer
{
dispatch_semaphore_t _in_flight_semaphore;
id <MTLDevice> _device;
id <MTLCommandQueue> _command_queue;
id <MTLRenderPipelineState> _pipeline_state;
id <MTLBuffer> _buffer_position;
id <MTLBuffer> _dynamic_uniform_buffer; //<新規>
uint8_t _uniform_buffer_index; //<新規>
}
-(nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)view;
{
//頂点データ
float vertices_array[]={
0.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0,
};
if(self= [super init])
{
_device = view.device;
_in_flight_semaphore = dispatch_semaphore_create(MaxBuffersInFlight);
view.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
_command_queue = [_device newCommandQueue];
//頂点情報の登録
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);
}
//パラメータバッファの登録<新規>
NSUInteger uniform_buffer_size = kAlignedUniformsSize * MaxBuffersInFlight;
_dynamic_uniform_buffer = [_device newBufferWithLength:uniform_buffer_size
options:MTLResourceStorageModeShared];
}
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)
{
_uniform_buffer_index = (_uniform_buffer_index + 1) % MaxBuffersInFlight;
//パラメータの更新<新規>
uint32_t uniform_buffer_offset = kAlignedUniformsSize * _uniform_buffer_index;
void* uniform_buffer_address = ((uint8_t*)_dynamic_uniform_buffer.contents) + uniform_buffer_offset;
Uniforms * uniforms = (Uniforms*)uniform_buffer_address;
uniforms->color[0] = 0.0f; // R 色指定
uniforms->color[1] = 0.0f; // G
uniforms->color[2] = 1.0f; // B
id <MTLRenderCommandEncoder> render_encoder = [command_buffer renderCommandEncoderWithDescriptor:render_pass_descriptor];
//パラメータの設定<新規>
[render_encoder setFragmentBuffer:_dynamic_uniform_buffer
offset:uniform_buffer_offset
atIndex:BufferIndexUniforms];
//モデルの設定
[render_encoder setRenderPipelineState:_pipeline_state];
[render_encoder setVertexBuffer:_buffer_position
offset:0
atIndex:BufferIndexPositions];
[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