IOS & OpenGL & OpenGL ES & Metal

First, the effect drawing

Ii. Comparison with GLSL loading triangle process

Three, the code part

1, the ViewController. M

#import "ViewController.h" #import "YRender.h" @interface ViewController () { MTKView *_view; YRender *_render; } @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; / / 1, _view = [[MTKView alloc] initWithFrame: CGRectMake (0, 0, the self. The frame. The size, width, the self. The frame. The size, height)); [self.view addSubview:_view]; / / 2, create a default device _view. The device = MTLCreateSystemDefaultDevice (); // if (! _view.device) { NSLog(@"Metal is not supported on this device"); return; } _render = [[YRender alloc]initWithMetalKitView:_view]; // if (! _render) { NSLog(@"Renderer failed initialization"); return; } //6, set the MTKView delegate (CustomRender) _view.delegate = _render; / / 7, set the frame rate, that is, how many frames _view. Call a rendering agent method preferredFramesPerSecond = 60; [_render mtkView:_view drawableSizeWillChange:_view.drawableSize]; } @endCopy the code

2, YShaderTypes. H

This is a bridge file, just create a new header file

# ifNdef YShaderTypes_h #define YShaderTypes_h // Purpose: to bridge parts shared between metal Shader and OC code. // A single class is used for this code, Typedef enum CCVertexInputIndex {// VertexinputIndex {// vertexinputIndex CCVertexInputIndexViewportSize CCVertexInputIndexVertices = 0, / / view size = 1,} CCVertexInputIndex; Vector_float4 position; // Vector_float4 position; // vector_float4 position; // RGBA color vector_float4 color; } CCVertex; #endif /* YShaderTypes_h */Copy the code

3, YShaders. Metal

Metal file

#include <metal_stdlib> using namespace metal; #import "yshadertypes. h" // Define a vertex shader output and fragment shader input typedef struct {// Handle spatial vertex information float4 clipSpacePosition [[position]]; // color float4 color; } RasterizerData; // vertex shader function RasterizerData function return value vertexShader function name pass argument (variable type variable name [[variable index position in buffer, ]) */ vertex RasterizerData vertexShader(uint vertexID [[vertex_id]], constant CCVertex *vertices [[buffer(CCVertexInputIndexVertices)]], Constant vector_uint2 * viewportSizePointer [[buffer (CCVertexInputIndexViewportSize)]]) {/ * processing vertex data: 2) Pass the vertex color value to the return value */ // define out RasterizerData out; out.clipSpacePosition = vertices[vertexID].position; out.color = vertices[vertexID].color; return out; } // fragment shader /* fragment shader modifier float4 Return value Type fragmentShader Function name Passed in parameters (variable type Variable name [[index position of the variable in the buffer, Fragment Float4 fragmentShader(RasterizerData in [[stage_in]]) [[stage_in]] {// Return in.color; }Copy the code

4, YRender. H

Apple suggests a separate rendering class

#import <Foundation/ foundation. h> #import <MetalKit/ metalkit. h> #import "yshadertypes.h" NS_ASSUME_NONNULL_BEGIN @interface YRender : NSObject<MTKViewDelegate> -(id)initWithMetalKitView:(MTKView *)mtkView; @end NS_ASSUME_NONNULL_ENDCopy the code

5, YRender. M

#import "YRender. H "@implementation YRender #import "YRender. H" @implementation YRender // Our render pipeline has vertex shaders and chip shaders stored in the. Metal shader file id<MTLRenderPipelineState> _pipelineState; <MTLCommandQueue> _commandQueue; Vector_uint2_viewportsize; } // init method -(id)initWithMetalKitView:(MTKView *) MTKView {self = [super init]; If (self) {//1, get the GPU device _device = mtkView.device; <MTLLibrary> defaultLibrary = [_device newDefaultLibrary]; VertexFun = [defaultLibrary newFunctionWithName:@"vertexShader"]; <MTLFunction> fragmentFun = [defaultLibrary newFunctionWithName:@"fragmentShader"]; / / 3, configuration used to create the rendering pipeline descriptor / / 1) create the pipe descriptor MTLRenderPipelineDescriptor * pipelineDes = [[MTLRenderPipelineDescriptor alloc] init]; //2) Name descriptor pipelineDes. Label = @"myPipelineDes"; / / 3) vertex function for each vertex in the process of the rendering pipelineDes. VertexFunction = vertexFun; / / 4) function, which is used to handle each fragment in the process of rendering/fragment pipelineDes fragmentFunction = fragmentFun; / / 5) a set of color data storage component pipelineDes. ColorAttachments [0]. PixelFormat = mtkView. ColorPixelFormat; NSError *error = NULL; _pipelineState = [_device newRenderPipelineStateWithDescriptor:pipelineDes error:&error]; // judge if (! _pipelineState) {NSLog(@"Failed to create pipeline state, error %@", error); return nil; _commandQueue = [_device newCommandQueue]; } return self; // static const CCVertex triangleVertices[] = {// static const CCVertex triangleVertices[] = {// static const CCVertex triangleVertices[] = { / / vertices, RGBA color value {{0.5, 0.25, 0.0, 1.0}, {1, 0, 0, 1}}, {{0.5, 0.25, 0.0, 1.0}, {0, 1, 0, 1}}, {{0.0 f, 0.25, 0.0, 1.0}, {0, 0, 1, 1}},}; <MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer]; commandBuffer.label = @"myCommandBuffer"; / / 3, create, render descriptor MTLRenderPassDescriptor * renderPassDescriptor = the currentRenderPassDescriptor; If (renderPassDescriptor! = nil) {// RenderEncoder id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor]; // Name renderEncoder. Label = @"myEncoder"; /* typedef struct {double originX, originY, width, height, znear, zfar; } MTLViewport; */ MTLViewport viewPort = {0.0, 0.0, _viewportSize. X, _viewportSize. [renderEncoder setViewport:viewPort]; RenderEncoder setRenderPipelineState:_pipelineState]; / / 7, the vertex data from the oc sent to the vertex shader function of metal / * 1: the parameters to pass data memory pointer parameter 2: to transfer data memory size parameters of the 3: The integer index must correspond to the index of the vertexShader buffer attribute qualifier ** Note that this method is used only if the data size cannot exceed 4096 bytes. More than the other methods in the * / [renderEncoder setVertexBytes: triangleVertices length: sizeof (triangleVertices) atIndex:CCVertexInputIndexVertices]; [renderEncoder setVertexBytes:&_viewportSize length:sizeof(_viewportSize) atIndex:CCVertexInputIndexViewportSize]; / / 8, the course of preparing, set the primitive connection mode [renderEncoder drawPrimitives: MTLPrimitiveTypeTriangle vertexStart: 0 vertexCount: 3]; RenderEncoder endEncoding = renderEncoder endEncoding; renderEncoder endEncoding = renderEncoder endEncoding; / / 10, once the frame buffer is completed, with the current drawing schedule, submitting render [commandBuffer presentDrawable: the currentDrawable]; } //11, render, push commandBuffer to GPU [commandBuffer commit]; } - (void)mtkView:(mtkView *)view drawableSizeWillChange:(CGSize)size {// save the drawable size because when we draw, We will pass these values to the vertex shader _viewPortsie.x = sie.width; _viewportSize.y = size.height; } @endCopy the code

Source link

Link: pan.baidu.com/s/1VVG_BzNO… Password: zvy9