如何在 Metal 中离线 render/export frame?
How to render/export frames offline in Metal?
我是 Metal 的新手,我能够实现在屏幕上旋转四边形的简单场景,但我想导出 1 分钟 video/frames 而不必实时执行。
所以想想用户只是打开应用程序并点击 'export button' 并且 cpu/gpu 全速输出 1 分钟 video/frames 的四边形旋转而不预览它。
我知道如何使用 AVFoundation 将帧转换为视频,但不知道如何在不实时进行的情况下将我的 3d 场景转换为帧。
谁能告诉我在哪里看?
非常感谢!
我改编了我的答案 and the Apple Metal game template to create this sample,它演示了如何直接从 Metal 渲染的一系列帧中录制视频文件。
由于 Metal 中的所有渲染都绘制到纹理,因此调整普通 Metal 代码使其适合离线渲染到电影文件中并不难。回顾一下核心录制过程:
- 创建一个
AVAssetWriter
以您的 URL 选择为目标
- 创建
.video
类型的 AVAssetWriterInput
,以便您可以编写视频帧
- 将
AVAssetWriterInputPixelBufferAdaptor
包裹在输入周围,这样您就可以将 CVPixelBuffer
作为帧附加到视频中
- 开始记录后,每一帧,将渲染帧纹理中的像素复制到从适配器的像素缓冲池中获取的像素缓冲区中。
- 完成后,将输入标记为已完成并完成写入资产编写器。
至于驱动录音,因为您没有从 MTKView
或 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)
}
}
如果您的渲染和记录代码是异步和线程安全的,您可以将其放在后台队列中以保持您的界面响应。如果你的渲染需要很长时间,你也可以加入一个进度回调来更新你的UI。
请注意,由于您不是实时 运行,因此您需要确保任何动画都考虑到当前帧时间(或帧之间的时间步长),因此事情 运行 以适当的速率播放。在我的示例中,我通过让立方体的旋转直接取决于帧的呈现时间来实现这一点。
我是 Metal 的新手,我能够实现在屏幕上旋转四边形的简单场景,但我想导出 1 分钟 video/frames 而不必实时执行。 所以想想用户只是打开应用程序并点击 'export button' 并且 cpu/gpu 全速输出 1 分钟 video/frames 的四边形旋转而不预览它。
我知道如何使用 AVFoundation 将帧转换为视频,但不知道如何在不实时进行的情况下将我的 3d 场景转换为帧。
谁能告诉我在哪里看?
非常感谢!
我改编了我的答案
由于 Metal 中的所有渲染都绘制到纹理,因此调整普通 Metal 代码使其适合离线渲染到电影文件中并不难。回顾一下核心录制过程:
- 创建一个
AVAssetWriter
以您的 URL 选择为目标 - 创建
.video
类型的AVAssetWriterInput
,以便您可以编写视频帧 - 将
AVAssetWriterInputPixelBufferAdaptor
包裹在输入周围,这样您就可以将CVPixelBuffer
作为帧附加到视频中 - 开始记录后,每一帧,将渲染帧纹理中的像素复制到从适配器的像素缓冲池中获取的像素缓冲区中。
- 完成后,将输入标记为已完成并完成写入资产编写器。
至于驱动录音,因为您没有从 MTKView
或 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)
}
}
如果您的渲染和记录代码是异步和线程安全的,您可以将其放在后台队列中以保持您的界面响应。如果你的渲染需要很长时间,你也可以加入一个进度回调来更新你的UI。
请注意,由于您不是实时 运行,因此您需要确保任何动画都考虑到当前帧时间(或帧之间的时间步长),因此事情 运行 以适当的速率播放。在我的示例中,我通过让立方体的旋转直接取决于帧的呈现时间来实现这一点。