ARKit – 如何显示来自放置在 SCNPlane 上的虚拟 SCNCamera 的源?

ZAY*_*ZAY 6 augmented-reality scenekit swift scncamera arkit

我使用 ARKit 和 SceneKit 将一些对象放入 AR 空间中。效果很好。现在我想添加一个额外的摄像机 (SCNCamera),该摄像机放置在场景中的其他位置,由公共 SCNNode 连接和定位。它旨在从另一个(固定)角度向我展示当前场景。

现在我想在 i.Ex 上展示这个额外的 SCNCamera feed。SCNPlane(作为漫反射第一种材质)- 就像电视屏幕一样。当然,我知道它只会显示位于相机焦点中的 SceneKit 内容,而不显示 ARKit 图像的其余部分(当然这只能由主相机实现)。那么简单的彩色背景就可以了。

我看过描述如何在 ARSpace 中的虚拟显示器上播放视频文件的教程,但我需要来自我自己当前场景的实时摄像机反馈。

我定义了这个对象:

let camera = SCNCamera()
let cameraNode = SCNNode()
Run Code Online (Sandbox Code Playgroud)

然后在 viewDidLoad 中我这样做:

camera.usesOrthographicProjection = true
camera.orthographicScale = 9
camera.zNear = 0
camera.zFar = 100
cameraNode.camera = camera
sceneView.scene.rootNode.addChildNode(cameraNode)
Run Code Online (Sandbox Code Playgroud)

然后我调用我的设置函数,将虚拟显示器放置在所有 AR 东西旁边,同时定位相机节点(指向对象在场景中停留的方向)

cameraNode.position = SCNVector3(initialStartPosition.x, initialStartPosition.y + 0.5, initialStartPosition.z)

let cameraPlane = SCNNode(geometry: SCNPlane(width: 0.5, height: 0.3))
cameraPlane.geometry?.firstMaterial?.diffuse.contents = cameraNode.camera
cameraPlane.position = SCNVector3(initialStartPosition.x - 1.0, initialStartPosition.y + 0.5, initialStartPosition.z)

sceneView.scene.rootNode.addChildNode(cameraPlane)
Run Code Online (Sandbox Code Playgroud)

一切都编译并加载...显示显示在给定位置,但它保持完全灰色。我放在场景中的 SCNCamera 根本没有显示任何内容。AR 场景中的其他一切都运行良好,只是我没有从该摄像头获得任何反馈。

灰色平面代替相机馈送

有谁有办法让这个场景发挥作用吗?

为了更好地可视化,我添加了一些更多的打印屏幕。

下面显示了根据 ARGeo 输入的 SCNCamera 的图像。但它需要整个屏幕,而不是像我需要的那样在 SCNPlane 上显示其内容。

从SCNCamera查看

下一个打印屏幕实际上显示了我使用发布的代码获得的当前 ARView 结果。正如您所看到的,灰色显示平面仍然是灰色的 - 它什么也不显示。

当前 AR 视图

最后一个打印屏幕是蒙太奇照片,显示了我想要得到的预期结果。

预期或期望的 AR 视图

这怎么能实现呢?我在这里错过了一些基本的东西吗?

ZAY*_*ZAY 6

经过一番研究和睡眠后,我得出了以下可行的解决方案(包括一些无法解释的障碍):

目前,附加的 SCNCamera feed 未链接到 SCNPlane 上的 SCNMaterial,因为这是最初的想法,但我将使用附加的 SCNView(目前)

在定义中我添加了另一个视图,如下所示:

let overlayView   = SCNView() // (also tested with ARSCNView(), no difference)
let camera        = SCNCamera()
let cameraNode    = SCNNode()
Run Code Online (Sandbox Code Playgroud)

然后,在 viewDidLoad 中,我设置了这样的东西......

camera.automaticallyAdjustsZRange = true
camera.usesOrthographicProjection = false
cameraNode.camera                 = camera
cameraNode.camera?.focalLength    = 50
sceneView.scene.rootNode.addChildNode(cameraNode) // add the node to the default scene

overlayView.scene                    = scene // the same scene as sceneView
overlayView.allowsCameraControl      = false
overlayView.isUserInteractionEnabled = false
overlayView.pointOfView              = cameraNode // this links the new SCNView to the created SCNCamera
self.view.addSubview(overlayView)    // don't forget to add as subview

// Size and place the view on the bottom
overlayView.frame  = CGRect(x: 0, y: 0, width: self.view.bounds.width * 0.8, height: self.view.bounds.height * 0.25)
overlayView.center = CGPoint(x: self.view.bounds.width * 0.5, y: self.view.bounds.height - 175)
Run Code Online (Sandbox Code Playgroud)

然后,在其他一些函数中,我将包含 SCNCamera 的节点放置到我想要的位置和角度。

// (exemplary)
cameraNode.position = initialStartPosition + SCNVector3(x: -0.5, y: 0.5, z: -(Float(shiftCurrentDistance * 2.0 - 2.0)))          
cameraNode.eulerAngles = SCNVector3(-15.0.degreesToRadians, -15.0.degreesToRadians, 0.0)
Run Code Online (Sandbox Code Playgroud)

结果是屏幕底部出现一种窗口(新的 SCNView),显示与主场景视图中相同的 SceneKit 内容,通过 SCNCamera 的视角及其节点位置进行查看,效果非常好。

主要 AR 视图以及其他视角的附加视图

在常见的 iOS/Swift/ARKit 项目中,这种构造会产生一些可能难以解决的副作用。

1) 主要是,新的 SCNView 从所需的角度显示 SceneKit 内容,但背景始终是实际的物理摄像机源。我无法弄清楚如何通过仍然显示所有 SceneKit 内容来使背景成为静态颜色。更改新场景的背景属性也会影响整个主场景,这实际上是不希望的。

2)这可能听起来令人困惑,但是一旦包含以下代码(这对于使其工作至关重要):

overlayView.scene = scene
Run Code Online (Sandbox Code Playgroud)

整个场景的动画速度(两者)双倍!(为什么?)

我通过添加/更改以下属性来纠正此问题,该属性恢复动画速度行为几乎像正常(默认)一样:

// add or change this in the scene setup
scene.physicsWorld.speed = 0.5
Run Code Online (Sandbox Code Playgroud)

3)如果项目中有像 SCNAction.playAudio 这样的动作,所有效果将不再播放 - 只要我不这样做:

overlayView.scene = nil
Run Code Online (Sandbox Code Playgroud)

当然,附加的 SCNView 停止工作,但其他一切都会恢复正常。


ARG*_*Geo 0

使用此代码(作为起点)了解如何设置虚拟相机。

只需在 Xcode 中创建一个默认的 ARKit 项目并复制粘贴我的代码:

import UIKit
import SceneKit
import ARKit

class ViewController: UIViewController, ARSCNViewDelegate {

    @IBOutlet var sceneView: ARSCNView!

    override func viewDidLoad() {
        super.viewDidLoad()
        sceneView.delegate = self
        sceneView.showsStatistics = true
        let scene = SCNScene(named: "art.scnassets/ship.scn")!
        sceneView.scene = scene

        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        cameraNode.position = SCNVector3(0, 0, 1)
        cameraNode.camera?.focalLength = 70
        cameraNode.camera?.categoryBitMask = 1
        scene.rootNode.addChildNode(cameraNode)

        sceneView.pointOfView = cameraNode
        sceneView.allowsCameraControl = true
        sceneView.backgroundColor = UIColor.darkGray

        let plane = SCNNode(geometry: SCNPlane(width: 0.8, height: 0.45))
        plane.position = SCNVector3(0, 0, -1.5)

        // ASSIGN A VIDEO STREAM FROM SCENEKIT-RECORDER TO YOUR MATERIAL
        plane.geometry?.materials.first?.diffuse.contents = capturedVideoFromSceneKitRecorder
        scene.rootNode.addChildNode(plane)
    }
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        let configuration = ARWorldTrackingConfiguration()
        sceneView.session.run(configuration)
    }
}
Run Code Online (Sandbox Code Playgroud)

更新

这是一个SceneKit Recorder 应用程序,您可以根据需要进行定制(您不需要将视频写入磁盘,只需使用流CVPixelBuffer并将其指定为漫反射材质的纹理)。

在此输入图像描述

希望这可以帮助。