创建一个MetalKit视图和一个渲染过程以绘制视图的内容。
纵览
在这个示例中,你将学习使用Metal 渲染图形内容的基础知识。你将使用MetalKit 框架创建一个视图并用Metal 来绘制视图的内容。然后,你将编码为视图设置背景颜色的渲染过程中的命令。
注意
MetalKit自动执行窗口系统任务,加载纹理并处理3D模型数据。阅读MetalKit来了解更多信息。
准备要绘制的MetalKit 视图
metalKit 提供一个叫MTKView的类, 它是NSView(在macOS中)或者UIView(在iOS 和 tvOS中)的子类,MTKView处理许多与将用Metal绘制的内容显示在屏幕上相关的细节。
为了在内部创建资源,MTKView需要对Metal设备对象的引用,因此,第一步是将视图的device属性设置为现有的MTLDevice。
_view.device = MTLCreateSystemDefaultDevice();
MTKView上的其他属性允许你控制其行为,将视图内容擦除为纯背景色,设置它的clearColor属性。通过MTLClearColorMake()函数创建颜色,指定红色、绿色、蓝色和alpha值。
_view.clearColor = MTLClearColorMake(0.0, 0.5, 1.0, 1.0);
因为在这个示例中不会绘制动画内容,所以配置视图,使其仅在需要更新内容时绘制。
_view.enableSetNeedsDisplay = YES;
代理绘图任务
MTKView依赖于您的应用程序向Metal发出命令以生成可视内容。MTKView使用代理模式通知应用程序何时应该绘制。为了接受代理的回调,将视图的delegate属性设置为符合MTKViewDelegate协议的对象。
_view.delegate = _renderer;
代理实现了两个方法:
1.每当内容大小发生变化时,视图将调用mtkView:drawableSizeWillChange:方法,这种变化在包含视图的窗口调整大小时,或者当设备方向发生变化时(在iOS上)发生。这允许应用程序根据视图的大小调整渲染时的分辨率。
2.每当到刷新视图内容的时间时,视图会调用drawInMTKView:方法。在这个方法中创建一个命令缓冲区,编码命令告诉GPU画什么和什么时候现在在屏幕上,然后在将要由GPU执行的命令缓冲区中排队。这个有时候称为画框。你可以把一个框架看作是产生一个在屏幕上显示的单一图像的所有工作。在一个交互式App中,比如游戏, 你可能每秒钟画很多框架。
在这个示例中,一个叫AAPLRenderer的类实现了代理方法并承担绘图的责任。视图控制器创建这个类的一个实例并把它设置为视图的代理。
创建渲染过程描述符
当你绘图,GPU会把结果存储到纹理中,纹理是包含图像数据的内存块,可被GPU访问。在本示例中,MTKView将创建需要绘制到视图中的所有纹理。它创建多个纹理,以便在渲染到另一个纹理时显示一个纹理的内容。
要进行绘制,请创建一个渲染过程,该过程是一系列渲染命令,这些命令绘制成一组纹理。在渲染过程中使用时,纹理也被称为渲染目标。若要创建渲染过程,需要一个渲染过程描述符,即MTLRenderPassDescriptor的实例。在这个示例中,与其配置自己的渲染过程描述符,不如让MetalKit 给你创建一个。
MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor;
if (renderPassDescriptor == nil)
{
return;
}
一个渲染过程描述符描述一组渲染目标,以及在渲染过程开始和结束时应如何处理这些目标。渲染过程还定义了渲染的某些其他方面,这些方面不是此例的一部分。该视图返回一个渲染过程描述符,该描述符具有指向该视图的某个纹理的单色附件,并根据该视图的属性配置渲染过程。默认情况下,这意味着渲染过程开始时,渲染目标将被擦除为纯色来匹配视图的clearColor属性,并且在渲染过程结束时所有更改都存储回纹理。
一个一个视图的渲染过程描述符可能为nil, 在创建渲染过程之前, 应该确保渲染过程描述符对象不为nil。
创建一个渲染过程
通过使用 MTLRenderCommandEncoder对象将其编码到命令缓冲区来创建渲染过程。调用命令缓冲区的render>CommandEncoderWithDescriptor:方法并在渲染过程描述符中传递。
id<MTLRenderCommandEncoder> commandEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
在本示例中,您不编码任何绘图命令,因此渲染过程只会删除纹理。调用编码器的endEncoding方法以指示该过程已完成。
[commandEncoder endEncoding];
在屏幕上呈现一幅图画
绘制到纹理不会自动在屏幕上显示新内容。实际上, 只有一些纹理可以显示在屏幕上。Metal中,可以在屏幕上显示的纹理由drawable对象管理,要显示内容,请显示可绘制对象。
MTKView自动创建可绘制对象来管理它的纹理,读取currentDrawable
属性以获取拥有作为渲染过程目标的纹理的drawable。视图返回一个CAMetalDrawable
对象,一个连接到核心动画的对象。
id<MTLDrawable> drawable = view.currentDrawable;
在命令缓冲区中调用presentDrawable:方法,传递drawable。
[commandBuffer presentDrawable:drawable];
此方法告诉Metal,当计划执行命令缓冲区时,Metal应与核心动画协调以在渲染完成后显示纹理。当核心动画呈现纹理时,它将成为视图的新内容。在本示例中,这意味着删除的纹理将成为视图的新背景。这种变化与核心动画为屏幕用户界面元素所做的任何其他视觉更新一起发生。
提交命令缓冲区
现在已经发出了帧的所有命令,提交命令缓冲区。
[commandBuffer commit];