iOS 如何将 3D SceneKit 内容合成到 GPU 上的视频帧上?

How do you composite 3D SceneKit content onto video frames on the GPU on iOS?

我正在开发 AR 应用程序。我有一个 SceneKit 场景被渲染到 SCNView(使用 OpenGL ES 作为渲染 API)。下面是另一个显示相机实时预览的视图。我想创建一个包含视频和 3D 场景的电影。

我正在使用基于 Apple 的 RosyWriter 示例代码的代码来处理带有 OpenGL 着色器的视频帧像素缓冲区。我认为我对这些概念的理解还不够好,因为我不确定如何在视频帧上叠加 SceneKit 渲染。我可以从 SCNView/SCNSceneRenderer 获取像素缓冲区,还是需要使用 SCNRenderer 将场景重新渲染为 OpenGL 捕获管道用于处理视频帧的屏幕外缓冲区中的纹理?

在 iOS11 中,现在有一种技术不仅可以轻松地在视频上叠加 SceneKit,还可以实现整个增强现实体验:ARKit。 (此外,如果您正在滚动自己的 AR 跟踪技术位想要使用 SceneKit 显示,在 iOS 11 中,您可以将 AVCaptureDevice 设置为任何 SceneKit material 属性,包括场景的背景。)

对于旧的 iOS 版本,以下建议仍然适用...


如果您已经有使用 OpenGL(或 Metal,就此而言)渲染的内容,并且您想要向其中添加 SceneKit 内容,请使用 SCNRenderer。就像使用 SCNView 一样在其上设置一个场景,按照通常的方式进行所有现有的 OpenGL 渲染,然后调用 renderAtTime:.

只是为了证明概念,这里有一个 非常快速的技巧 RosyWriter 上添加 SceneKit 渲染。下面的所有代码都进入 RosyWriterOpenGLRenderer.m.

在实例变量的声明中:

@interface RosyWriterOpenGLRenderer ()
{
    //... existing ivars, plus:
    SCNRenderer *_scnRenderer;
}

init中,设置后_oglContext

_scnRenderer = [SCNRenderer rendererWithContext:_oglContext options:nil];
SCNScene *scene = [SCNScene scene];
SCNNode *node = [SCNNode nodeWithGeometry:[SCNBox geometry]];
[node runAction:[SCNAction repeatActionForever:[SCNAction rotateByX:1 y:1 z:1 duration:1]]];
[scene.rootNode addChildNode:node];
_scnRenderer.scene = scene;

copyRenderedPixelBuffer 中,在对 glFlush()bail 标签的现有调用之间:

glFlush();

[_scnRenderer renderAtTime:CFAbsoluteTimeGetCurrent()];

bail:

这足以在实时视频视图和录制的电影输出中获得一个旋转的大白色立方体。 (它只是因为默认 material 和照明设置而没有阴影。对于实际用例,设置灯光、materials、相机、您想要的几何形状等)