如何在 Metal 中离线渲染/导出帧?

mas*_*na2 4 3d avfoundation swift metal

我是 Metal 的新手,我能够在屏幕上实现一个简单的简单场景 Quad 旋转,但我想导出 1 分钟的视频/帧而无需实时执行。因此,考虑一下用户只需打开应用程序并点击“导出按钮”,cpu/gpu 就会全速输出 1 分钟视频/四轮旋转的帧而无需预览它。

我知道如何使用 AVFoundation 将帧转换为视频,但不知道如何在不实时执行的情况下将我的 3d 场景转换为帧。

有人可以指出我在哪里看吗?

非常感谢!

war*_*enm 9

在这里修改了我的答案和 Apple Metal 游戏模板来创建这个示例,它演示了如何直接从 Metal 渲染的帧序列中录制视频文件。

由于 Metal 中的所有渲染都绘制到纹理,因此改编普通 Metal 代码并使其适合离线渲染到电影文件中并不难。回顾一下核心录制过程:

  • 创建一个AVAssetWriter以您选择的 URL 为目标的
  • 创建一个AVAssetWriterInput类型,.video以便您可以编写视频帧
  • 环绕AVAssetWriterInputPixelBufferAdaptor输入,以便您可以将CVPixelBuffers 作为帧附加到视频中
  • 在您开始记录每一帧后,将渲染帧纹理中的像素复制到从适配器的像素缓冲池中获取的像素缓冲区中。
  • 完成后,将输入标记为完成并完成写入资产编写器。

至于驱动录音,由于您没有从MTKViewor获得委托回调CADisplayLink,您需要自己完成。基本模式如下所示:

for t in stride(from: 0, through: duration, by: frameDelta) {
    draw(in: renderBuffer, depthTexture: depthBuffer, time: t) { (texture) in
        recorder.writeFrame(forTexture: texture, time: t)
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您的渲染和录制代码是异步且线程安全的,您可以将其放在后台队列中以保持您的界面响应。如果您的渲染需要很长时间,您还可以使用进度回调来更新您的 UI。

请注意,由于您不是实时运行,因此您需要确保任何动画都考虑到当前帧时间(或帧之间的时间步长),以便在播放时以正确的速率运行。在我的示例中,我通过让立方体的旋转直接依赖于帧的呈现时间来做到这一点。