4

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

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

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

我定义了这个对象:

let camera = SCNCamera()
let cameraNode = SCNNode()

然后在 viewDidLoad 我这样做:

camera.usesOrthographicProjection = true
camera.orthographicScale = 9
camera.zNear = 0
camera.zFar = 100
cameraNode.camera = camera
sceneView.scene.rootNode.addChildNode(cameraNode)

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

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)

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

灰色平面而不是相机馈送

有没有人想办法让这种情况发挥作用?

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

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

从 SCNCamera 观看

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

当前的 AR 视图

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

预期或期望的 AR 视图

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

4

2 回答 2

4

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

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

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

let overlayView   = SCNView() // (also tested with ARSCNView(), no difference)
let camera        = SCNCamera()
let cameraNode    = SCNNode()

然后,在 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)

然后,在其他一些函数中,我将包含 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)

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

主 AR 视图加上其他视角的附加视图

在一个常见的 iOS/Swift/ARKit 项目中,这种结构会产生一些副作用,人们可能会遇到这种情况。

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

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

overlayView.scene = scene

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

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

// add or change this in the scene setup
scene.physicsWorld.speed = 0.5

3)如果项目中有SCNAction.playAudio之类的动作,所有的效果都不会再播放了——只要我不这样做:

overlayView.scene = nil

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

于 2019-05-11T16:35:09.700 回答
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)
    }
}

更新

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

在此处输入图像描述

希望这可以帮助。

于 2019-05-09T05:57:48.017 回答