首页 文章

ARKit - ARRreferenceImage跟踪

提问于
浏览
0

我正在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 回答

  • 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)
            }
    
    }
    

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

相关问题