首页 > 解决方案 > ARKit – 海报作为虚拟房间的窗口

问题描述

我正在使用 ARKit 开发 iOS 应用程序。

在现实世界中,墙上有一张海报。海报是固定的东西,因此可以应用任何需要的预处理。

目标是让这张海报成为进入虚拟房间的窗口。这样当用户接近海报时,他可以“透过”它在某个虚拟 3D 环境(房间)中查看。当然,用户不能穿过“窗口”然后在那个 3D 环境中漫游。他只能“透过”海报观察虚拟房间。

我知道可以让 ARKit 检测到这张海报,并在它周围播放一些视觉效果,甚至在它上面播放一部电影。

但我没有找到如何将其变成虚拟 3D 世界的窗口的信息。

非常感谢任何想法和示例项目的链接。

标签: swiftscenekitaugmented-realityarkitrealitykit

解决方案


查看在增强图像网页上发布的此视频(使用 Chrome 浏览器观看此视频)。

创建这种类型的虚拟立方体很容易。您只需要一个没有正面多边形的简单立方体基元的 3D 模型(以便查看其内表面)。你还需要一架带方孔的飞机。为这个平面分配一个开箱即用的RealityKit 遮挡材质或手工制作的SceneKit 遮挡材质,它将隐藏立方体的所有外墙(见下图)。

在 Autodesk Maya中,遮挡材质是渲染统计中的一个保留选项(仅适用于 Viewport 2.0):

在此处输入图像描述

当您将在墙上跟踪您的海报时(启用detectionImages选项),您的应用程序必须识别图片并使用遮挡着色器“加载”3D 立方体及其遮罩平面。因此,如果ARImageAnchor在海报上和pivot point3D 立方体必须相遇,则立方体的轴心点必须位于立方体的前边缘(与墙壁表面相同的水平)。

如果您想下载 Apple 的包含图像检测体验的示例代码 - 只需单击与 detectionImages 相同的网页上的蓝色按钮。

这是我的代码的一个简短示例:

@IBOutlet var sceneView: ARSCNView!

override func viewDidLoad() {
    super.viewDidLoad()

    sceneView.delegate = self  // for using renderer() methods of ARSCNViewDelegate
    sceneView.scene = SCNScene()
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    resetTrackingConfiguration()
}


func resetTrackingConfiguration() {

    guard let refImage = ARReferenceImage.referenceImages(inGroupNamed: "Poster", 
                                                                bundle: nil) 
    else { return }

    let config = ARWorldTrackingConfiguration()
    config.detectionImages = refImage
    config.maximumNumberOfTrackedImages = 1

    let options = [ARSession.RunOptions.removeExistingAnchors,
                   ARSession.RunOptions.resetTracking]

    sceneView.session.run(config, options: ARSession.RunOptions(options))
}

...当然还有 SceneKit 的renderer()实例方法:

func renderer(_ renderer: SCNSceneRenderer,
             didAdd node: SCNNode,
              for anchor: ARAnchor) {

    guard let imageAnchor = anchor as? ARImageAnchor,
          let _ = imageAnchor.referenceImage.name 

    else { return }

    anchorsArray.append(imageAnchor)

    if anchorsArray.first != nil {
        node.addChildNode(portalNode)
    }
}

推荐阅读