ARKit - ARRreferenceImage跟踪

时间:2018-03-23 20:56:57

标签: ios11 arkit

我正在使用ARKit中的ARReferenceImages,我正在尝试在识别参考图像时添加SCNNode,然后将该节点留在原位,无论是否在其他地方识别出相同的参考图像。

我可以正确添加我的SCNode,但是如果我移动我的标记,它会再次拾取它并将我放置的节点移动到标记的位置。

我要添加的代码如下:

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
        guard let imageAnchor = anchor as? ARImageAnchor else { return }
        let referenceImage = imageAnchor.referenceImage
        print("MAPNODE IS NIL = \(self.mapNode == nil)")
        updateQueue.async {
            if self.mapNode == nil {

            // Create a plane to visualize the initial position of the detected image.
            let plane = SCNPlane(width: 1.2912,
                                 height: 1.2912)
            let planeNode = SCNNode(geometry: plane)
            planeNode.opacity = 1

            /*
             `SCNPlane` is vertically oriented in its local coordinate space, but
             `ARImageAnchor` assumes the image is horizontal in its local space, so
             rotate the plane to match.
             */
            planeNode.eulerAngles.x = -.pi / 2

            self.mapNode = planeNode
            /*
             Image anchors are not tracked after initial detection, so create an
             animation that limits the duration for which the plane visualization appears.
             */
            // Add the plane visualization to the scene.
            node.addChildNode(planeNode)
            }
        }
 }

在这里阅读文档https://developer.apple.com/documentation/arkit/recognizing_images_in_an_ar_experience#2958517它说明了

  

应用最佳实践

     

此示例应用程序只是可视化ARKit检测每个引用的位置   在用户环境中的图像,但您的应用程序可以做更多。跟随   以下提示设计使用图像检测的AR体验。

     

使用检测到的图像设置AR场景的参照系。   而不是要求用户选择虚拟内容的位置,   或者任意地将内容放置在用户的环境中,使用检测到的   用于锚定虚拟场景的图像。您甚至可以使用多个检测到的   图片。例如,零售商店的应用程序可以创建虚拟应用程序   通过认识,角色似乎从商店的前门出现   海报放在门的两边,然后计算一个   角色直接在海报之间的位置。

     

请注意

     

使用ARSession setWorldOrigin(relativeTransform :)方法   重新定义世界坐标系,以便您可以放置​​所有锚点   以及与您选择的参考点相关的其他内容。

     

设计您的AR体验,以将检测到的图像作为起点   用于虚拟内容。 ARKit不跟踪位置的变化或   每个检测到的图像的方向。如果您尝试放置虚拟   保持附着在检测到的图像上的内容,该内容可能不会   似乎正确地保持在原位。相反,使用检测到的图像作为   用于启动动态场景的参考框架。例如,您的应用   可能会认出科幻电影的剧院海报然后有   虚拟宇宙飞船似乎从海报中出现并飞来飞去   环境。

所以我尝试将我的世界变换设置为等于我的图像锚点的变换

 self.session.setWorldOrigin(relativeTransform: imageAnchor.transform)

然而,我的mapNode跟随imageAnchor移动到哪里。我还没有实现renderer update方法,所以我不确定为什么会继续这样做。

我假设setWorldOrigin方法不断更新到imageAnchor.transform,而不仅仅是那个时刻,这很奇怪,因为该代码只被调用一次。有什么想法吗?

1 个答案:

答案 0 :(得分:1)

如果要在ARImageAnchor的位置添加mapNode,可以在ARImageAnchor的变换处设置mapNode的位置,并将其添加到场景中但不链接到参考图像,如果这是有道理的。

这可以这样做:

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

        //1. If Out Target Image Has Been Detected Than Get The Corresponding Anchor
        guard let currentImageAnchor = anchor as? ARImageAnchor else { return }

        //2. An ImageAnchor Is Only Added Once For Each Identified Target
        print("Anchor ID = \(currentImageAnchor.identifier)")

        //3. Add An SCNNode At The Position Of The Identified ImageTarget
        let nodeHolder = SCNNode()

        let nodeGeometry = SCNBox(width: 0.02, height: 0.02, length: 0.02, chamferRadius: 0)
        nodeGeometry.firstMaterial?.diffuse.contents = UIColor.cyan
        nodeHolder.geometry = nodeGeometry

        nodeHolder.position = SCNVector3(currentImageAnchor.transform.columns.3.x,
                                         currentImageAnchor.transform.columns.3.y,
                                         currentImageAnchor.transform.columns.3.z)

        augmentedRealityView?.scene.rootNode.addChildNode(nodeHolder)

 }

在问题的另一部分,您似乎暗示您想要检测同一图像的多次出现。我可能错了,但我认为唯一的方法是删除参考图像的相应ARImageAnchor,这可以这样做(通过在最后一个代码片段的末尾添加它):

 augmentedRealitySession.remove(anchor: currentImageAnchor)

这里的问题是,一旦ARImageAnchor被删除,任何时候再次检测到它,你将不得不处理是否应该添加内容,这是棘手的,因为ARImageAnchor.identifier始终是相同的对于referenceImage而言,无论是否被删除然后重新添加,因此难以存储在dictionary等。因此根据您的需要,您需要找到一种方法来确定是否内容存在于该位置以及是否重新添加等。

关于setWorldOrigin的问题的最后一部分似乎有些奇怪,就像你说的那样,但也许你可以添加一个Bool来防止它发生潜在的变化,例如:

var hasSetWorldOrigin = false

然后基于此,你可以确保它只设置一次,例如:

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

        //1. If Out Target Image Has Been Detected Than Get The Corresponding Anchor
        guard let currentImageAnchor = anchor as? ARImageAnchor else { return }


        //2. If We Havent Set The World Origin Set It Based On The ImageAnchorTranform
        if !hasSetWorldOrigin{

            self.augmentedRealitySession.setWorldOrigin(relativeTransform: currentImageAnchor.transform)
            hasSetWorldOrigin = true

            //3. Create Two Nodes To Add To The Scene And Distribute Them
            let nodeHolderA = SCNNode()
            let nodeGeometryA = SCNBox(width: 0.04, height: 0.04, length: 0.04, chamferRadius: 0)
            nodeGeometryA.firstMaterial?.diffuse.contents = UIColor.green
            nodeHolderA.geometry = nodeGeometryA

            let nodeHolderB = SCNNode()
            let nodeGeometryB = SCNBox(width: 0.04, height: 0.04, length: 0.04, chamferRadius: 0)
            nodeGeometryB.firstMaterial?.diffuse.contents = UIColor.red
            nodeHolderB.geometry = nodeGeometryB

            if let cameraTransform = augmentedRealitySession.currentFrame?.camera.transform{
                nodeHolderA.simdPosition =  float3(cameraTransform.columns.3.x,
                                                   cameraTransform.columns.3.y,
                                                   cameraTransform.columns.3.z)

                nodeHolderB.simdPosition =  float3(cameraTransform.columns.3.x + 0.2,
                                                   cameraTransform.columns.3.y,
                                                   cameraTransform.columns.3.z)
            }


            augmentedRealityView?.scene.rootNode.addChildNode(nodeHolderA)
            augmentedRealityView?.scene.rootNode.addChildNode(nodeHolderB)
        }

}

希望我的回答能为你提供一个有用的起点,当然我已经正确地解释了你的问题,