创建MetalView
self.mtkView.device = MTLCreateSystemDefaultDevice(); // 获取默认的device
self.view = self.mtkView;
self.mtkView.delegate = self;
self.viewportSize = (vector_uint2){self.mtkView.drawableSize.width, self.mtkView.drawableSize.height};
创建pipeline
id<MTLLibrary> defaultLibrary = [self.mtkView.device newDefaultLibrary]; // .metal
id<MTLFunction> vertexFunction = [defaultLibrary newFunctionWithName:@"vertexShader"]; // 顶点shader,vertexShader是函数名
id<MTLFunction> fragmentFunction = [defaultLibrary newFunctionWithName:@"samplingShader"]; // 片元shader,samplingShader是函数名
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
pipelineStateDescriptor.vertexFunction = vertexFunction;
pipelineStateDescriptor.fragmentFunction = fragmentFunction;
pipelineStateDescriptor.colorAttachments[0].pixelFormat = self.mtkView.colorPixelFormat;
self.pipelineState = [self.mtkView.device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor
error:NULL]; // 创建图形渲染管道,耗性能操作不宜频繁调用
self.commandQueue = [self.mtkView.device newCommandQueue]; // CommandQueue是渲染指令队列,保证渲染指令有序地提交到GPU
创建顶点矩阵
static const LYVertex quadVertices[] =
{ // 顶点坐标,分别是x、y、z、w; 纹理坐标,x、y;
{ { 0.5, -0.5, 0.0, 1.0 }, { 1.f, 1.f } },
{ { -0.5, -0.5, 0.0, 1.0 }, { 0.f, 1.f } },
{ { -0.5, 0.5, 0.0, 1.0 }, { 0.f, 0.f } },
{ { 0.5, -0.5, 0.0, 1.0 }, { 1.f, 1.f } },
{ { -0.5, 0.5, 0.0, 1.0 }, { 0.f, 0.f } },
{ { 0.5, 0.5, 0.0, 1.0 }, { 1.f, 0.f } },
};
self.vertices = [self.mtkView.device newBufferWithBytes:quadVertices
length:sizeof(quadVertices)
options:MTLResourceStorageModeShared]; // 创建顶点缓存
self.numVertices = sizeof(quadVertices) / sizeof(LYVertex); // 顶点个数
创建纹理
- (void)setupTexture {
UIImage *image = [UIImage imageNamed:@"abc"];
// 纹理描述符
MTLTextureDescriptor *textureDescriptor = [[MTLTextureDescriptor alloc] init];
textureDescriptor.pixelFormat = MTLPixelFormatRGBA8Unorm;
textureDescriptor.width = image.size.width;
textureDescriptor.height = image.size.height;
self.texture = [self.mtkView.device newTextureWithDescriptor:textureDescriptor]; // 创建纹理
MTLRegion region = {{ 0, 0, 0 }, {image.size.width, image.size.height, 1}}; // 纹理上传的范围
Byte *imageBytes = [self loadImage:image];
if (imageBytes) { // UIImage的数据需要转成二进制才能上传,且不用jpg、png的NSData
[self.texture replaceRegion:region
mipmapLevel:0
withBytes:imageBytes
bytesPerRow:4 * image.size.width];
free(imageBytes); // 需要释放资源
imageBytes = NULL;
}
}
- (Byte *)loadImage:(UIImage *)image {
// 1获取图片的CGImageRef
CGImageRef spriteImage = image.CGImage;
// 2 读取图片的大小
size_t width = CGImageGetWidth(spriteImage);
size_t height = CGImageGetHeight(spriteImage);
Byte * spriteData = (Byte *) calloc(width * height * 4, sizeof(Byte)); //rgba共4个byte
CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4,
CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
// 3在CGContextRef上绘图
CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);
CGContextRelease(spriteContext);
return spriteData;
}
渲染
// 每次渲染都要单独创建一个CommandBuffer
id<MTLCommandBuffer> commandBuffer = [self.commandQueue commandBuffer];
MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor;
// MTLRenderPassDescriptor描述一系列attachments的值,类似GL的FrameBuffer;同时也用来创建MTLRenderCommandEncoder
if(renderPassDescriptor != nil)
{
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.5, 0.5, 1.0f); // 设置默认颜色
id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor]; //编码绘制指令的Encoder
[renderEncoder setViewport:(MTLViewport){0.0, 0.0, self.viewportSize.x, self.viewportSize.y, -1.0, 1.0 }]; // 设置显示区域
[renderEncoder setRenderPipelineState:self.pipelineState]; // 设置渲染管道,以保证顶点和片元两个shader会被调用
[renderEncoder setVertexBuffer:self.vertices
offset:0
atIndex:0]; // 设置顶点缓存
[renderEncoder setFragmentTexture:self.texture
atIndex:0]; // 设置纹理
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle
vertexStart:0
vertexCount:self.numVertices]; // 绘制
[renderEncoder endEncoding]; // 结束
[commandBuffer presentDrawable:view.currentDrawable]; // 显示
}
[commandBuffer commit]; // 提交;
名词解释
- vertex:顶点函数
- fragment: 片元函数
- buffer: vertex参数,小括号模具代表了encoder设置VertexBuffer的index,
- texture: 输入纹理,小括号枚举代表了encoder设置的texture的index
疑问点
- sharder是怎么绑定的