编写完Metal顶点函数和片元函数后,我们需要在OC代码中使用并传递数据到函数中。当然,MetalKit提供了相关的API,相比于OpenGL ES,Metal的API是面对对象的。
相关类学习
MTLLibrary
MTLLibrary
是用来承载着色函数的容器,它是一个不需要开发者实现的协议,一个MTLLibrary
对象附着了Metal着色语言的源码,它会在程序编译或运行时将Metal文件从字符串形式编译链接到程序中,不需要开发者像OpenGL ES一样对着色器进行编译连接,Metal帮我们完成了这一过程。
MTLLibrary
对象由MTLDevice
对象创建,MTLDevice
有以下方法:
- newDefalutLibrary
- newLibraryWithFile:error:
- newLibraryWithData:error:
- newLibraryWithSource:options:completionHandler:
- newLibraryWithSource:options:error:
MTLFunction
MTLFunction
相当于一个着色函数,同样是一个不需要开发者实现的协议,在MTLLibrary
协议种提供了相应的方法newFunctionWithName:
,让我们可以根据着色器函数名得到对应的函数对象。
- (id<MTLFunction>)newFunctionWithName:(NSString *)functionName;
MTLRenderPipelineDescriptor
MTLRenderPipelineDescriptor
是一个用来获得渲染管道对象的类。
一个MTLRenderPipelineDescriptor
对象是被用来创建MTLRenderPipelineState
对象的,我们可以使用MTLRenderPipelineDescriptor
对象将着色器函数MTLFunction
附着到渲染管道上,同时也可以设置缓冲区,包括顶点缓冲区、颜色缓冲区、深度缓冲区和模版缓冲区,这些在OpenGL ES中是添加到上下文中去的,而在Metal中,通过MTLRenderPipelineDescriptor
对象进行设置就可以完成。
常见的API有:
@property(readwrite, nonatomic, strong) id<MTLFunction> vertexFunction;
@property(readwrite, nonatomic, strong) id<MTLFunction> fragmentFunction;
@property(readonly) MTLPipelineBufferDescriptorArray *vertexBuffers;
@property(readonly) MTLPipelineBufferDescriptorArray *fragmentBuffers;
@property(readonly) MTLRenderPipelineColorAttachmentDescriptorArray *colorAttachments;
@property(nonatomic) MTLPixelFormat depthAttachmentPixelFormat;
@property(nonatomic) MTLPixelFormat stencilAttachmentPixelFormat;
MTLRenderPipelineState
顾名思义,MTLRenderPipelineState
就是指渲染管道,它是一个不需要开发实现的协议。由MTLDevice
创建。
相比于OpenGL ES抽象渲染管道概念,Metal是将其具化为一个轻量级对象,而要创建一个管道对象,我们需要先创建一个MTLRenderPipelineDescriptor
对象,由MTLDevice
对象创建。
MTLDevice
有以下方法创建管道:
- (id<MTLRenderPipelineState>)newRenderPipelineStateWithDescriptor:(MTLRenderPipelineDescriptor *)descriptor error:(NSError * _Nullable *)error;
- (id<MTLRenderPipelineState>)newRenderPipelineStateWithDescriptor:(MTLRenderPipelineDescriptor *)descriptor options:(MTLPipelineOption)options reflection:(MTLAutoreleasedRenderPipelineReflection *)reflection error:(NSError * _Nullable *)error;
- (void)newRenderPipelineStateWithDescriptor:(MTLRenderPipelineDescriptor *)descriptor completionHandler:(MTLNewRenderPipelineStateCompletionHandler)completionHandler;
- (void)newRenderPipelineStateWithDescriptor:(MTLRenderPipelineDescriptor *)descriptor options:(MTLPipelineOption)options completionHandler:(MTLNewRenderPipelineStateWithReflectionCompletionHandler)completionHandler;
而如果要往这条管道的一端传输数据,就需要借助MTLRenderCommandEncoder
对象。
MTLRenderCommandEncoder
MTLRenderCommandEncoder
是填充命令缓冲区的一种编码器,它同样是一个不需要开发者实现的协议,它的对象由可以从命令缓冲区MTLCommandBuffer
获得。
- (id<MTLRenderCommandEncoder>)renderCommandEncoderWithDescriptor:(MTLRenderPassDescriptor *)renderPassDescriptor;
MTLRenderPassDescriptor
是渲染描述对象,可以由MTKView
的currentRenderPassDescriptor
属性获得
我们很多渲染指令都是通过编码器进行传递,最终通过命令缓冲区完成渲染指令的,常用的API有:
// 设置当前渲染管道状态对象
- (void)setRenderPipelineState:(id<MTLRenderPipelineState>)pipelineState;
// 设置填充方式,有线段和面两种
- (void)setTriangleFillMode:(MTLTriangleFillMode)fillMode;
// 设置正背面
- (void)setFrontFacingWinding:(MTLWinding)frontFacingWinding;
// 设置正背面剔除模式
- (void)setCullMode:(MTLCullMode)cullMode;
// 设置深度缓冲区
- (void)setDepthStencilState:(id<MTLDepthStencilState>)depthStencilState;
// 深度缓冲区参数配置相关方法
- (void)setDepthBias:(float)depthBias slopeScale:(float)slopeScale clamp:(float)clamp;
- (void)setDepthClipMode:(MTLDepthClipMode)depthClipMode;
// 设置视口
- (void)setViewport:(MTLViewport)viewport;
// 设置裁剪
- (void)setScissorRect:(MTLScissorRect)rect;
// 设置颜色混合
- (void)setBlendColorRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha;
// 从顶点缓冲区给顶点着色器函数发送数据
//*buffer 缓冲区
//*offset 偏移量
//*index 缓冲区的索引,与着色器函数的被传递参数的传递修饰符中的()的值需一致
- (void)setVertexBuffer:(id<MTLBuffer>)buffer offset:(NSUInteger)offset atIndex:(NSUInteger)index;
// 发送数据给顶点着色器
- (void)setVertexBytes:(const void *)bytes length:(NSUInteger)length atIndex:(NSUInteger)index;
// 从片元缓冲区给片元着色器函数发送数据
- (void)setFragmentBuffer:(id<MTLBuffer>)buffer offset:(NSUInteger)offset atIndex:(NSUInteger)index;
// 发送数据给片元着色器
- (void)setFragmentBytes:(const void *)bytes length:(NSUInteger)length atIndex:(NSUInteger)index;
// 设置图元连接方式和起始顶点及顶点数量
- (void)drawPrimitives:(MTLPrimitiveType)primitiveType vertexStart:(NSUInteger)vertexStart vertexCount:(NSUInteger)vertexCount;
// 表示已该编码器生成的命令都已完成,并且从MTLCommandBuffer中分离
- (void)endEncoding;
示例
附上简单渲染管道创建代码:
// 获取Metal Library
id<MTLLibrary> defaultLibrary = [_device newDefaultLibrary];
// 获取顶点着色函数
id<MTLFunction> vertexFunction = [defaultLibrary newFunctionWithName:@"vertexShader"];
// 获取片元着色函数
id<MTLFunction> fragmentFunction = [defaultLibrary newFunctionWithName:@"fragmentShader"];
// 创建渲染管道描述
MTLRenderPipelineDescriptor *pipelineDesc = [[MTLRenderPipelineDescriptor alloc] init];
pipelineDesc.label = @"my pipelineDesc";
// 设置顶点着色函数和片元着色函数
pipelineDesc.vertexFunction = vertexFunction;
pipelineDesc.fragmentFunction = fragmentFunction;
// 设置颜色像素格式
pipelineDesc.colorAttachments[0].pixelFormat = _mtkview.colorPixelFormat;
// 创建管道
NSError *error = nil;
_renderPipeline = [_device newRenderPipelineStateWithDescriptor:pipelineDesc error:&error];
if (error) {
NSLog(@"create pipeline failed: %@", error.description);
}
总结
这些类直接的关系可以用下图概括:

网友评论