美文网首页
Hello Metal

Hello Metal

作者: 远方竹叶 | 来源:发表于2020-08-25 11:22 被阅读0次

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

    实现效果如下:

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

    自定义渲染循环

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

    初始化

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

    • 设置 device
    _device = mtkView.device;
    

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

    • 设置命令队列
    _commanQueue = [_device newCommandQueue];
    

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

    Metal 命令对象之间的关系

    • 命令缓冲区(command buffer)是从命令队列中(command queue)创建的
    • 命令编码器(command encoders)将命令编码到命令缓冲区中
    • 提交命令缓冲区并将其发送到 GPU
    • GPU 执行命令并将结果呈现为可绘制

    设置颜色

    - (Color)makeFancyColor;
    

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

    实现代理协议

    MTKViewDelegate 需要实现两个代理方法

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

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

    • 获取颜色值
    Color color = [self makeFancyColor];
    

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

    • 设置 view 的清屏颜色
    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 对象

    • 创建 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 是不会直接绘制到屏幕上,因此你不给出去指令。是不会有任何内容渲染到屏幕上

    • 完成渲染并将命令缓冲区提交给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

    相关文章

      网友评论

          本文标题:Hello Metal

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