使用 Metal 绘制视图的内容

创建一个 MetalKit 视图和渲染通道以绘制视图的内容。

概述

在这个示例中,您将学习使用 Metal 渲染图形内容的基础知识。您将使用 MetalKit 框架创建一个利用 Metal 绘制视图内容的视图。然后,您将编码一个渲染通道的命令,以背景色擦除视图。

示例代码传送门

注意

MetalKit 自动化了窗口系统任务、加载纹理和处理 3D 模型数据。更多信息,请参见 MetalKit。

准备一个 MetalKit 视图以进行绘制

MetalKit 提供了一个名为 MTKView 的类,它是 NSView(在 macOS 中)或 UIView(在 iOS 和 tvOS 中)的子类。MTKView 处理了许多与将您使用 Metal 绘制的内容显示到屏幕上的相关细节。

MTKView 需要引用一个 Metal 设备对象,以便内部创建资源,因此您的第一步是将视图的 device 属性设置为现有的 MTLDevice。

objectiveC 复制代码
_view.device = MTLCreateSystemDefaultDevice();

MTKView 上的其他属性允许您控制其行为。要将视图的内容擦除为纯背景色,您需要设置其 clearColor 属性。您可以通过指定红、绿、蓝和 alpha 值使用 MTLClearColorMake(::::) 函数创建颜色。

objectiveC 复制代码
_view.clearColor = MTLClearColorMake(0.0, 0.5, 1.0, 1.0);

由于在此示例中您不会绘制动画内容,请配置视图,使其仅在需要更新内容时(例如当视图形状改变时)才进行绘制:

objectiveC 复制代码
_view.enableSetNeedsDisplay = YES;

委托绘制职责

MTKView 依赖您的应用程序向 Metal 发出命令以生成视觉内容。MTKView 使用委托模式在应该进行绘制时通知您的应用程序。要接收委托回调,请将视图的 delegate 属性设置为符合 MTKViewDelegate 协议的对象。

objectiveC 复制代码
_view.delegate = _renderer;

委托实现两个方法:

  • 当内容大小发生变化时,视图会调用 mtkView(_:drawableSizeWillChange:) 方法。这发生在包含视图的窗口被调整大小时,或在设备方向改变时(在 iOS 上)。这允许您的应用程序适应渲染分辨率以匹配视图的大小。
  • 当需要更新视图的内容时,视图会调用 draw(in:) 方法。在此方法中,您创建一个命令缓冲区,编码告诉 GPU 绘制什么内容以及何时在屏幕上显示它的命令,并将该命令缓冲区排队以供 GPU 执行。这有时被称为绘制一帧。您可以将帧视为生成显示在屏幕上的单个图像所需完成的所有工作。在交互式应用程序(如游戏)中,您每秒可能会绘制多帧。

在这个示例中,一个名为 AAPLRenderer 的类实现了委托方法并承担了绘制的责任。视图控制器创建此类的一个实例,并将其设置为视图的委托。

创建渲染通道描述符

当您绘制时,GPU 会将结果存储到纹理中,这些纹理是包含图像数据并可由 GPU 访问的内存块。在此示例中,MTKView 创建了绘制视图所需的所有纹理。它创建了多个纹理,以便能够在显示一个纹理的内容的同时向另一个纹理进行渲染。

要进行绘制,您需要创建一个渲染通道,即绘制到一组纹理的一系列渲染命令。在渲染通道中使用的纹理也称为渲染目标。要创建渲染通道,您需要一个渲染通道描述符,即 MTLRenderPassDescriptor 的实例。在此示例中,不是配置自己的渲染通道描述符,而是请求 MetalKit 视图为您的应用创建一个。

objectiveC 复制代码
MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor;
if (renderPassDescriptor == nil)
{
    return;
}

渲染通道描述符描述了一组渲染目标及其在渲染通道开始和结束时应如何处理。渲染通道还定义了一些不属于此示例的其他渲染方面。视图返回具有指向视图纹理之一的颜色附件的渲染通道描述符,并根据视图属性配置渲染通道。默认情况下,这意味着在渲染通道开始时,渲染目标会被擦除为与视图的 clearColor 属性匹配的纯色,在渲染通道结束时,所有更改都会保存回纹理。

因为视图的渲染通道描述符可能为 nil,所以在创建渲染通道之前,应该测试确保渲染通道描述符对象是非 nil 的。

创建渲染通道

通过使用 MTLRenderCommandEncoder 对象将其编码到命令缓冲区中来创建渲染通道。调用命令缓冲区的 makeRenderCommandEncoder(descriptor:) 方法并传入渲染通道描述符。

objectiveC 复制代码
id<MTLRenderCommandEncoder> commandEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];

在此示例中,您不编码任何绘制命令,因此渲染通道唯一做的事情就是擦除纹理。调用编码器的 endEncoding 方法以指示该通道已完成。

ObjectiveC 复制代码
[commandEncoder endEncoding];

将可绘制对象呈现到屏幕

绘制到纹理不会自动将新内容显示在屏幕上。实际上,只有某些纹理可以呈现在屏幕上。在 Metal 中,能够显示在屏幕上的纹理由可绘制对象管理,要显示内容,您需要呈现可绘制对象。

MTKView 自动创建可绘制对象来管理其纹理。读取 currentDrawable 属性以获取拥有渲染通道目标纹理的可绘制对象。视图返回一个 CAMetalDrawable 对象,这是一个连接到 Core Animation 的对象。

objectiveC 复制代码
id<MTLDrawable> drawable = view.currentDrawable;

调用命令缓冲区上的 present(_:) 方法,并传入可绘制对象。

objectiveC 复制代码
[commandBuffer presentDrawable:drawable];

此方法告诉 Metal 在命令缓冲区计划执行时,Metal 应与 Core Animation 协作在渲染完成后显示纹理。当 Core Animation 呈现纹理时,它将成为视图的新内容。在此示例中,这意味着被擦除的纹理将成为视图的新背景。这一变化与其他 Core Animation 为屏幕上用户界面元素所做的视觉更新同步发生。

提交命令缓冲区

既然已经发出了帧的所有命令,提交命令缓冲区。

objectiveC 复制代码
[commandBuffer commit];
相关推荐
恋猫de小郭12 小时前
Compose Multiplatform iOS 稳定版发布:可用于生产环境,并支持 hotload
android·flutter·macos·ios·kotlin·cocoa
WangMing_X14 小时前
Flutter开发IOS蓝牙APP的大坑
flutter·ios
AI逐月15 小时前
当新iPhone加入团队:一场 EAS CLI 与 Apple 生态的斗智斗勇
ios·cocoa·iphone
帅次1 天前
Flutter TabBar / TabBarView 详解
android·flutter·ios·小程序·iphone·taro·reactnative
安和昂1 天前
【iOS】 方法交换
macos·ios·cocoa
美狐美颜sdk1 天前
什么是美颜SDK?美颜SDK安卓与iOS端开发指南
android·人工智能·ios·音视频·美颜sdk·直播美颜sdk
Ya-Jun3 天前
性能优化实践:渲染性能优化
android·flutter·ios·性能优化
chennalC#c.h.JA Ptho3 天前
ios systeam introduction
经验分享·笔记·其他·macos·ios
Mysticbinary3 天前
消息验证码(MAC)的介绍
mac·hmac·认证加密
Ya-Jun3 天前
性能优化实践:性能监控体系
android·开发语言·flutter·ios·性能优化