Highlight
Metal 4 提供三层机器学习能力:MetalFX 提供开箱即用的神经降噪和上采样、ML Command Encoder 可在渲染管线中直接运行预训练模型、TensorOps API 让着色器内联运行小型神经网络,充分利用 M5 和 A19 Pro GPU 的神经加速器。
核心内容
实时渲染的机器语言困境
做实时渲染的开发者都会遇到一个矛盾:要画质就要多采样,要多采样帧率就扛不住。
比如路径追踪器(Path Tracer),要达到无噪点的图像,每像素需要数百次采样。但实时视口只能承受每像素 1 次采样——结果就是满屏噪点。
传统方案是各种降噪算法,但它们要么效果有限,要么计算成本太高。
Apple 的三层解决方案
Metal 4 提供了三层递进的机器学习能力:
第一层:MetalFX —— 黑盒解决方案,直接调用就能用
第二层:ML Command Encoder —— 把训练好的模型跑在渲染管线里
第三层:TensorOps API —— 在着色器里手写小型神经网络
MetalFX:即时可用的神经降噪
MetalFX Denoising 是一个神经上采样器和降噪器的组合,专门为 Apple silicon 优化。
Maxon 的 Redshift Live(Cinema 4D 的实时路径追踪视口)就采用了这个方案。开启后,原本充满噪点的单采样图像瞬间变得干净,还能保持实时帧率。
要获得最好的效果,有三个关键实践:
-
保持输入干净 —— 辅助输入(如 diffuse albedo)应该是无噪点的,这是降噪器最强的信号
-
存储观众看到的 —— 镜面反射存储反射几何体的属性,玻璃通过菲涅尔项混合反射和折射
-
运动矢量要正确 —— MetalFX 期望去抖动的运动矢量,没有次像素偏移
ML Command Encoder:替换后处理管线
降噪只是起点。后处理管线(色调映射、色彩分级、胶片模拟)同样可以用机器学习。
传统管线是多个阶段串联,每个阶段有自己的参数,整体可能变得很复杂。神经网络的思路是:学习整个色彩变换。
以 HDRNet 为例,它用下采样图像做全局和局部分析,为 16x16 图块生成局部变换,最后用边缘感知技术应用到全图。
工作流是这样的:在 PyTorch 中训练网络,导出为 MTLPackage,然后在 Metal 4 中加载和执行。
TensorOps:着色器内联微型网络
最激进的方案是在着色器里直接运行一个小型神经网络。
这类网络只有几千个参数,针对特定任务训练,甚至可以每帧在线训练。
举例:基于图像的光照(Image Based Lighting)传统需要预计算 irradiance map,但场景是动态的(日夜循环),预计算可能过时。
解决方案是用一个小型 MLP 在线学习这个信号,每帧运行几次训练迭代,模型就能实时适应新的世界状态。
详细内容
MetalFX 降噪集成
(02:16)
MetalFX Denoising 的集成很直接:路径追踪器生成颜色和一些辅助输入,MetalFX 输出降噪后的图像,之后继续你的后处理流程。
需要的辅助输入包括 diffuse albedo、深度等,如果你的渲染器已经产生这些,直接用就行。
去抖动运动矢量计算
(08:46)
正确计算运动矢量对时间稳定性至关重要。下面是计算静态物体相机-only 运动矢量的代码:
#include <metal_stdlib>
using namespace metal;
// 计算相机-only 运动矢量
float4 clipCurrent = viewProjCurrent * float4(worldPos, 1.0);
float2 ndcCurrent = clipCurrent.xy / clipCurrent.w;
float4 clipPrevious = viewProjPrevious * float4(worldPos, 1.0);
float2 ndcPrevious = clipPrevious.xy / clipPrevious.w;
float2 motion = ndcPrevious - ndcCurrent;
// 获取当前帧和上一帧的次像素偏移
float2 jitterCurrent = getJitter(frameIndex);
float2 jitterPrevious = getJitter(frameIndexPrevious);
motion -= jitterPrevious - jitterCurrent;
关键点:
- 通过当前和上一帧的视图投影矩阵变换世界位置
- 计算两个 NDC 坐标的差值得到运动矢量
- 减去抖动偏移,得到去抖动的干净运动矢量
对于移动或变形的物体,需要存储每个顶点的上一帧世界位置,或蒙皮两次,计算真实运动矢量。
ML Command Encoder 部署流程
(12:03)
部署神经网络需要两个步骤:
设置阶段:
- 加载 MTLPackage
- 用函数描述符指定网络函数
- 创建机器学习管线描述符
执行阶段:
- 创建编码器
- 创建参数表,绑定输入和输出
- 分发命令缓冲区
更新后的渲染管线:路径追踪 → MetalFX 降噪 → 神经色调映射,全部在同一个命令缓冲区中编码,同一帧内执行。
TensorOps 构建内联网络
(17:56)
神经网络由三部分组成:输入层、隐藏层、输出层。
以天空探头为例,这是一个 3-4-4-3 的 MLP(多层感知器):输入 3 个浮点数编码方向,输出 3 个浮点数表示该方向的平均光照颜色。
在着色器中评估网络的流程:
- 准备输入张量(最好是 2D 矩阵以批量处理)
- 使用
matmul2D 张量操作进行矩阵乘法 - 应用激活函数
- 重复到输出层
SIMD 群组执行模式:
(19:29)
使用 SIMD-group 执行范围时,所有参与的线程协同工作在同一个矩阵乘法上,还能访问协作张量。
协作张量的存储分布在线程组的多个线程之间,避免了昂贵的主存往返。用协作张量作为第一次乘法的输出,结果会留在快速的线程存储内存中,然后原地应用激活函数。
在线训练循环
(16:06)
在线训练改变了传统渲染循环:
- 生成一个希望采样的方向
- 在模型上运行推理获取结果
- 计算天空照明问题的解析解
- 使用解析解计算误差
- 运行反向传播逐步改进模型
这个流程可以在每一帧重复多次,模型就能实时适应新的世界条件,并用这个信息立即进行着色。
核心启发
-
动态 irradiance probe —— 为你的实时渲染器构建一个在线学习的 irradiance 网络。当场景光照变化时(开关灯、日夜循环),网络自动适应,无需重新预计算。入口:TensorOps API + 自定义训练循环
-
神经材质近似 —— 训练一个小型 MLP 学习复杂材质的响应。比如多层涂层、次表面散射等昂贵计算,可以用一个在着色器内联运行的微型网络近似。入口:ML Command Encoder 部署自定义网络
-
自适应后处理 —— 收集你项目中美术手动调色的图像对(HDR 原图 + 调色后结果),训练一个神经色调映射器。部署后,渲染器直接输出 HDR,网络自动完成风格化后处理。入口:PyTorch 训练 + MTLPackage 导出
-
实时 AI 辅助布光 —— 用小网络学习特定场景的布光偏好。美术调整几盏灯后,网络学习这个风格,然后可以快速应用到其他场景或自动生成类似布光方案。入口:TensorOps 在线学习
-
降噪强度自适应 —— 根据场景内容自动调整 MetalFX 的降噪强度。比如用一个小网络分析图像,为不同区域生成最优的 denoiser strength mask。入口:TensorOps + MetalFX strength mask
关联 Session
- What’s new in Metal — Metal 4 核心新特性总览
- Go further with Metal 4 games — MetalFX 降噪详细实践
- Combine Metal 4 machine learning and graphics — ML Command Encoder 和 TensorOps 深度讲解
- Metal tensors — 张量 API 性能优化
- Metal Performance Primitives (MPP) Programming Guide — 完整代码示例和 API 参考
评论
GitHub Issues · utterances