Metal 1
MetalKit
- MTKView
Metal 渲染管道
- 1.VertexData 通过CPU也就是我们的程序提供顶点数据
- VertexProcessing(VertexShader) -> PrimitiveAssembly -> Rasterization -> FragmentProcessing(FragmentShader) -> Framebuffer
VertexData(CPU) |
---|
Vertex Processing(VertexShader) |
Primitive Assembly [triangles,quads,lines,points] |
Rasterization |
Fragment Processing(FragmentShader) [textures,stencil,alpha,depth] |
Framebuffer (Screen Pixels) |
MTKView 内部有一个定时器,去执行重绘的动作(可以自定义关闭或暂停)
苹果官方建议:Saparate Your Rendering Loop (分离或者抽离你的渲染模块,这样的解释大家比较容易理解)
MTKViewDelegate 两个必须实现的代理方法
- 1.当窗口发生改变的时候会调用一个代理方法
-(void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size
- 2.当帧率确定之后,比方帧率为60,每个60帧会调用一次代理方法
-(void)drawInMTKView:(nonnull MTKView *)view
Metal Command Objects
- MTLDevice ->GPU
创建device
mtkview.device = MTLCreateSystemDefaultDevice();
- MTLCommandQueue 所有应用程序需要与GPU交互的第一对象(
也就是它先睡,睡完之后其他人才能睡
)
_commandQueue = [_device newCommandQueue];
- MTLCommandBuffer 为当前的每一个渲染传递创建一个新的命令缓冲区
id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
commandBuffer.label = @"command_1";
- 命令缓冲区(commandBuffer)是由命令队列(_commandQueue)创建的
- 命令编码器(commoand encoders)将命令编码到命令缓冲区中
- commit命令缓存区并将其提交到GPU
- GPU执行命令并将结果呈现为可绘制
理解:
1.命令时通过 command encoders 编译之后(编译这个字眼在OpenGLES就很熟悉了,方便理解)存储在 命令缓冲区中(commandBuffer)
2.然后通过命令缓冲区 驱动GPU完成绘制和显示的动作
3.Metal 不需要像OpenGLES一样需要自己编译和链接(毕竟是苹果爸爸的亲儿子,所以需要有神秘感)
【metal 1】
Metal 实践流程
- 1.如何向GPU 发送渲染命令
- 2.如何获取Metal设备
- 3.如何配置MetalKit
- 4.如何创建执行GPU指令
- 5.如何显示渲染内容
案例1:实现背景颜色的更迭
步骤一 创建RCRendering类继承自NSObject 并添加MTKViewDelegate
#import <Foundation/Foundation.h>
@import MetalKit;
NS_ASSUME_NONNULL_BEGIN
@interface RCRendering : NSObject<MTKViewDelegate>
-(id)initWithMetalkitview:(MTKView *)mtkview;
@end
NS_ASSUME_NONNULL_END
步骤二 RCRendering 的完整步骤(当然了作为一个完美的男人,关键的时刻是隐藏
)
1.定义私有变量
@implementation RCRendering
{
id<MTLDevice> _device;
id<MTLCommandQueue> _commandQueue;
}
2.定义一个颜色结构体
typedef struct {
float r,g,b,a;
}CustomColor;
3.设置想要的颜色
-(CustomColor)makeFancycolor{
// 用来判断是否增加颜色
static BOOL growing = YES;
// 创建一个颜色通道
static NSUInteger primaryChannel = 0;
static float colorChannels[] = {1.0,0.2,0.0,1.0};
const float dynamicColorrate = 0.015;
if (growing){
NSUInteger dynamicChannelIndex = (primaryChannel +1)%3;
colorChannels[dynamicChannelIndex] += dynamicColorrate;
if (colorChannels[dynamicChannelIndex]>=1.0){
growing = NO;
primaryChannel = dynamicChannelIndex;
}
}
else{
NSUInteger dynamicChannelIndex = (primaryChannel + 2)%3;
colorChannels[dynamicChannelIndex] -= dynamicColorrate;
if (colorChannels[dynamicChannelIndex]<=0.0){
growing = NO;
}
}
CustomColor color;
color.r = *colorChannels + 0;
color.g = *colorChannels + 1;
color.b = *colorChannels + 2;
color.a = *colorChannels + 3;
return color;
}
4.初始化方法
-(id)initWithMetalkitview:(MTKView *)mtkview{
self = [super init];
if (self){
_device = mtkview.device;
_commandQueue = [_device newCommandQueue];
}
return self;
}
5.MTKViewDelegate 方法
- -(void)drawInMTKView
-(void)drawInMTKView:(nonnull MTKView *)view {
// 拿到颜色值
CustomColor color = [self makeFancycolor];
// 清理背景颜色
view.clearColor = MTLClearColorMake(color.r, color.g, color.b, color.a);
// 创建commandbuffer
id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
commandBuffer.label = @"buffer_1";
// 创建渲染描述对象(会自动打印描述信息)
MTLRenderPassDescriptor *renderPD = view.currentRenderPassDescriptor;
if (!renderPD) return;
// 创建 command encoders
id<MTLCommandEncoder> commandEncoders = [commandBuffer parallelRenderCommandEncoderWithDescriptor:renderPD];
commandEncoders.label= @"command encoders";
/** 省略一些内容 主要是桥接metal文件的内容,关键部分隐藏就不告诉你*/
[commandEncoders endEncoding];
// 把帧缓冲区的内容渲染到屏幕上
[commandBuffer presentDrawable:view.currentDrawable];
// 提交GPU
[commandBuffer commit];
}
- -(void)mtkView:(nonnull MTKView *)view drawableSizeWillChange
-(void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size {
NSLog(@"%ld",(long)view.preferredFramesPerSecond);
NSLog(@"%ld",(long)view.currentRenderPassDescriptor);
}
6.viewcontroller 里面的实现
// MTL MTK
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_mtkView = (MTKView*)self.view;
_mtkView.device = MTLCreateSystemDefaultDevice();
if (!_mtkView.device) return;
_rcrender = [[RCRendering alloc] initWithMetalkitview:_mtkView];
if (!_rcrender) return;
_mtkView.delegate = _rcrender;
// 设置帧率
_mtkView.preferredFramesPerSecond = 60;
}
网友评论