ARKit - ARRreference图像跟踪

ARKit - ARRreferenceImage tracking

我在 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 它指出

Apply Best Practices

This example app simply visualizes where ARKit detects each reference image in the user’s environment, but your app can do much more. Follow the tips below to design AR experiences that use image detection well.

Use detected images to set a frame of reference for the AR scene. Instead of requiring the user to choose a place for virtual content, or arbitrarily placing content in the user’s environment, use detected images to anchor the virtual scene. You can even use multiple detected images. For example, an app for a retail store could make a virtual character appear to emerge from a store’s front door by recognizing posters placed on either side of the door and then calculating a position for the character directly between the posters.

Note

Use the ARSession setWorldOrigin(relativeTransform:) method to redefine the world coordinate system so that you can place all anchors and other content relative to the reference point you choose.

Design your AR experience to use detected images as a starting point for virtual content. ARKit doesn’t track changes to the position or orientation of each detected image. If you try to place virtual content that stays attached to a detected image, that content may not appear to stay in place correctly. Instead, use detected images as a frame of reference for starting a dynamic scene. For example, your app might recognize theater posters for a sci-fi film and then have virtual spaceships appear to emerge from the posters and fly around the environment.

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

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

但是我的 mapNode 跟随 imageAnchor 移动。我还没有实现 renderer update 方法,所以我不确定为什么会一直这样。

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

如果您想在 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 相同,无论它是否被删除,然后 re-added 因此很难存储在 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)
        }

}

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