今天看啥  ›  专栏  ›  清风烈酒2157

0021--OpenGL Metal 案例一 改变屏幕背景颜色

清风烈酒2157  · 简书  ·  · 2020-08-24 08:58

[toc]

前言

通过这个案例我们熟悉一下:
1.理理解 Metal 应⽤用程序
2.如何向 GPU发 送基本的渲染命令
3.如何获取 Metal 设备
4.如何配置 MetalKit 视图
5.如何创建并执⾏行行 GPU 指令
6.显示渲染的内容

准备工作

  1. 如果使用 SB ,修改 View 继承 MTKView
  2. 独立于平台的渲染类 QFRenderer

1. viewDidLoad函数

加载自定义的渲染视图 MTKView ,并将渲染交由自定的渲染循环类处理


   //1. 
    _view = (MTKView *)self.view;
    
   //2. 
    _view.device = MTLCreateSystemDefaultDevice();
    
    //3.
    if (!_view.device) {
        NSLog(@"Metal is not supported on this device");
        return;
    }
   //4.
    _render =[[QFRenderer alloc]initWithMetalKitView:_view];
    
   //5.
    if (!_render) {
        NSLog(@"Renderer failed initialization");
        return;
    }
    
   //6.
    _view.delegate = _render;
   //7. 
    _view.preferredFramesPerSecond = 60;
  1. 获取 MTKView 的实例 _view ;
  2. 设置 _view device ,一个 MTLDevice对象 就代表这着一个 GPU ,通常我们可以调用方法 MTLCreateSystemDefaultDevice() 来获取代表默认的GPU单个对象.
  3. 判断是否设置成功
  4. 分开你的渲染循环:在我们开发 Metal 程序时,将渲染循环分为自己创建的类,是非常有用的一种方式, 使用单独的类,我们可以更好管理初始化 Metal ,以及 Metal 视图委托.
  5. 判断_render 是否创建成功
  6. 设置 MTKView 的代理`
  7. 视图可以根据视图属性上设置帧速率(指定时间来调用 drawInMTKView 方法--视图需要渲染时调用)

2. 渲染循环类

处理 metal 渲染的相关操作

1. 创建 GPU 和命令队列


@interface QFRenderer()
{
    id<MTLDevice> _device;
    id<MTLCommandQueue> _commandQueue;
}
@end

2. 初始化,对 _device _commandQueue 进行赋值

- (id)initWithMetalKitView:(MTKView *)mtkView
{
    self = [super init];
    if(self)
    {
        _device = mtkView.device;
        _commandQueue = [_device newCommandQueue];
    }
    
    return self;
}

所有应用程序需要与 GPU 交互的第一个对象是一个对象。 MTLCommandQueue .你使用 MTLCommandQueue 去创建对象,并且加入 MTLCommandBuffer 对象中.确保它们能够按照正确顺序发送到 GPU .对于每一帧,一个新的 MTLCommandBuffer 对象创建并且填满了由 GPU 执行的命令.

3. 创建一个返回一组随机颜色的方法

//这个函数用来创建一个颜色
- (Color)makeFancyColor{
   //1. 增加颜色/减小颜色的 标记
   static BOOL       growing = YES;
   //2.颜色通道值(0~3)
   static NSUInteger primaryChannel = 0;
   //3.颜色通道数组colorChannels(颜色值)
   static float      colorChannels[] = {1.0, 0.0, 0.0, 1.0};
   //4.颜色调整步长
   const float DynamicColorRate = 0.015;
    
   
  //5.判断
    if(growing)
    {
        //动态信道索引 (1,2,3,0)通道间切换
        NSUInteger dynamicChannelIndex = (primaryChannel+1)%3;
        
        //修改对应通道的颜色值 调整0.015
        colorChannels[dynamicChannelIndex] += DynamicColorRate;
        
        //当颜色通道对应的颜色值 = 1.0
        if(colorChannels[dynamicChannelIndex] >= 1.0)
        {
            //设置为NO
            growing = NO;
            
            //将颜色通道修改为动态颜色通道
            primaryChannel = dynamicChannelIndex;
        }
    }
    else
    {
        //获取动态颜色通道
        NSUInteger dynamicChannelIndex = (primaryChannel+2)%3;
        
        //将当前颜色的值 减去0.015
        colorChannels[dynamicChannelIndex] -= DynamicColorRate;
        
        //当颜色值小于等于0.0
        if(colorChannels[dynamicChannelIndex] <= 0.0)
        {
            //又调整为颜色增加
            growing = YES;
        }
    }

    Color color;
    color.red = colorChannels[0];
    color.green = colorChannels[1];
    color.blue = colorChannels[2];
    color.alpha = colorChannels[3];
    return color;
}

MTKViewDelegate

4. MTKViewDelegate

  • drawInMTKView
  1. 获取颜色值
  2. 设置 view clearColor
  3. 使用 MTLCommandQueue 创建对象并且加入到 MTCommandBuffer 对象中去.为当前渲染的每个渲染传递创建一个新的命令缓冲区
  4. 从视图绘制中,获得渲染描述符
  5. 判断 renderPassDescriptor 渲染描述符是否创建成功,否则则跳过任何渲染.
  6. 通过渲染描述符 renderPassDescriptor 创建 MTLRenderCommandEncoder 对象
  7. 我们可以使用 MTLRenderCommandEncoder 来绘制对象,但是这个 demo 我们仅仅创建编码器就可以了,我们并没有让 Metal 去执行我们绘制的东西,这个时候表示我们的任务已经完成
    即可结束 MTLRenderCommandEncoder 工作
  8. 当编码器结束之后,命令缓存区就会接受到 2 个命令.
  1. present 2. commit
    因为 GPU 是不会直接绘制到屏幕上,因此你不给出去指令.是不会有任何内容渲染到屏幕上.
  1. 在这里完成渲染并将命令缓冲区提交给GPU

- (void)drawInMTKView:(MTKView *)view{
    
    //1.
    Color color = [self makeFancyColor];
    view.clearColor = MTLClearColorMake(color.red, color.green, color.blue, color.alpha);
    
    id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
    commandBuffer.label = @"commandBuffer";
    MTLRenderPassDescriptor *renderPassDescriptor  = view.currentRenderPassDescriptor;
    
    if (!renderPassDescriptor){ return;}
    id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
    renderEncoder.label = @"renderEncoder";
    [renderEncoder endEncoding];
   
   // 添加一个最后的命令来显示清除的可绘制的屏幕
   [commandBuffer presentDrawable:view.currentDrawable];
    [commandBuffer commit];
}

以上几个步骤,在 metal 渲染中几乎都要使用到,需要牢记!!

  • drawableSizeWillChange
  • (void)mtkView:(MTKView *)view drawableSizeWillChange:(CGSize)size{

}

效果图

颜色变化.gif




原文地址:访问原文地址
快照地址: 访问文章快照