Hello Metal

2020-08-25  本文已影响0人  远方竹叶

本文为了了解 Metal 以及实现一个简单的颜色变化案例

实现效果如下:

本案例分为两大类,自定义渲染循环和控制器的调用

自定义渲染循环

在我们开发 Metal 程序时,将渲染循环分为自己创建的类,是非常有用的一种方式,使用单独的类,我们可以更好管理初始化 Metal 以及 Metal 视图委托。自定义渲染循环主要包括三大模块

初始化

需要传入一个 MTKView 对象,通过传入的 view,获取 Metal 设备以及创建命令队列

_device = mtkView.device;

此处的 device 并不是新建的,是由传入 view 在外面创建好的,可以通过 view 获取

_commanQueue = [_device newCommandQueue];

所有应用程序需要与 GPU 交互的第一个对象是 MTLCommandQueue 对象。使用 MTLCommandQueue 去创建对象,并且加入 MTLCommandBuffer 对象中,为当前渲染的每个渲染传递创建一个新的命令缓冲区

Metal 命令对象之间的关系

设置颜色

- (Color)makeFancyColor;

随着帧率变化的颜色,详细可见文末完整代码链接

实现代理协议

MTKViewDelegate 需要实现两个代理方法

// 每当视图需要渲染时调用
- (void)drawInMTKView:(nonnull MTKView *)view;

根据视图(view)属性上设置帧速率,每当到指定时间时,就会触发 view 的渲染,继而回调 drawInMTKView: 代理方法进行绘制渲染。

Color color = [self makeFancyColor];

通过 makeFancyColor 函数获取当前帧显示的颜色

view.clearColor = MTLClearColorMake(color.red, color.green, color.blue, color.alpha);

类似 OpenGL ES 中的 glClearColor

id<MTLCommandBuffer> commandBuffer = [_commanQueue commandBuffer];
commandBuffer.label = @"MyCommand";

使用 MTLCommandQueue 创建对象并且加入到 MTCommandBuffer 对象中去,为当前渲染的每个渲染传递创建一个新的命令缓冲区

MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor;

从视图(view)属性中获取,用于在 commandBuffer 中创建 MTLRenderCommandEncoder 对象

id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
renderEncoder.label = @"MyRenderEncoder";

通过渲染描述符 renderPassDescriptor 创建 MTLRenderCommandEncoder 对象,即命令渲染编辑器,相当于 OpenGL ES 中的 program,主要用途是用于绘制对象

[renderEncoder endEncoding];

任务已经完成,不需要绘制,结束 MTLRenderCommandEncoder 工作

[commandBuffer presentDrawable:view.currentDrawable];

当编码器结束之后,命令缓存区就会接受到2个命令:
1) present;
2) commit。

因为 GPU 是不会直接绘制到屏幕上,因此你不给出去指令。是不会有任何内容渲染到屏幕上

[commandBuffer commit];

相当于 OpenGL ES 中的 调用 draw

- (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size;

当 MTKView 视图发生大小改变时调用,这个案例没用到,就不多解释了,后面会跟进

控制器调用

主要是加载 view 以及 view 传递给 render 渲染循环类

创建 MTKView 对象

_view = [[MTKView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:_view];

MTKView 继承自 UIView,可以调用 initWithFrame: 方法

为 MTKView 对象设置 device

_view.device = MTLCreateSystemDefaultDevice();

一个 MTLDevice 对象就代表这着一个 GPU,通常我们可以调用方法MTLCreateSystemDefaultDevice() 来获取代表默认的 GPU 单个对象

创建 LcRender

_render = [[LcRender alloc] initWithMetalKitView:_view];

在我们开发 Metal 程序时,将渲染循环分为自己创建的类,是非常有用的一种方式,使用单独的类,我们可以更好管理初始化 Metal 以及 Metal 视图委托

设置代理

_view.delegate = _render;

由 LcRender 来实现 MTKView 的代理方法

设置帧速率

_view.preferredFramesPerSecond = 60;

视图可以根据视图属性上设置帧速率,即指定时间来调用 drawInMTKView 方法--视图需要渲染时调用

完整代码见GitHub Hello Metal

上一篇下一篇

猜你喜欢

热点阅读