美文网首页Metal
Metal学习笔记(三)-- Metal着色器函数的使用

Metal学习笔记(三)-- Metal着色器函数的使用

作者: iOSer_jia | 来源:发表于2020-08-25 16:51 被阅读0次

编写完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是渲染描述对象,可以由MTKViewcurrentRenderPassDescriptor属性获得

我们很多渲染指令都是通过编码器进行传递,最终通过命令缓冲区完成渲染指令的,常用的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);
}

总结

这些类直接的关系可以用下图概括:

Metal关系图.png

相关文章

网友评论

    本文标题:Metal学习笔记(三)-- Metal着色器函数的使用

    本文链接:https://www.haomeiwen.com/subject/glyzjktx.html