Get All ARAnchors of focused Camera in ARKIT

2019-04-01 23:25发布

问题:

When application launched first a vertical surface is detected on one wall than camera focus to the second wall, in the second wall another surface is detected. The first wall is now no more visible to the ARCamera but this code is providing me the anchors of the first wall. but I need anchors of the second wall which is right now Visible/focused in camera.

if let anchor = sceneView.session.currentFrame?.anchors.first {
    let node = sceneView.node(for: anchor)
    addNode(position: SCNVector3Zero, anchorNode: node)
} else {
    debugPrint("anchor node is nil")
}

回答1:

In order to get the node that is currently is in point of view you can do something like this:

       var targettedAnchorNode: SCNNode?
       if let anchors = sceneView.session.currentFrame?.anchors {
           for anchor in anchors {

               if let anchorNode = sceneView.node(for: anchor), let pointOfView = sceneView.pointOfView, sceneView.isNode(anchorNode, insideFrustumOf: pointOfView) {
                   targettedAnchorNode = anchorNode
                   break
               }
           }

           if let targettedAnchorNode = targettedAnchorNode {
               addNode(position: SCNVector3Zero, anchorNode: targettedAnchorNode)
           } else {
               debugPrint("Targetted node not found")
           }

       } else {
           debugPrint("Anchors not found")
       }

If you would like to get all focused nodes, collect them in an array satisfying specified condition

Good luck!



回答2:

The clue to the answer is in the beginning line of your if let statement.

Lets break this down:

When you say let anchor = sceneView.session.currentFrame?.anchors.first, you are referencing an optional array of ARAnchor, which naturally can have more than one element.

Since your are always calling first e.g. index [0], you will always get the 1st ARAnchor which was added to the array.

Since you now have 2 anchors, you would naturally need the last (latest) element. As such you can try this as a starter:

if let anchor = sceneView.session.currentFrame?.anchors.last {

    let node = sceneView.node(for: anchor)
    addNode(position: SCNVector3Zero, anchorNode: node)

     } else {

        debugPrint("anchor node is nil")
}

Update: Since another poster has interpreted the question differently, in that they believe the question is how can I detect if an ARPlaneAnchor is in view? Let's approach it another way.

First we need to take into consideration that the ARCamera has a Frostrum in which our content is shown:

As such, we would then need to determine whether an ARPlaneAnchor was inViewOfFrostrum.

First we will create 2 variables:

var planesDetected = [ARPlaneAnchor: SCNNode]()
var planeID: Int = 0

The 1st to store the ARPlaneAnchor and its associated SCNNode, and the 2nd in order to provide a unique ID for each plane.

In the ARSCNViewDelegate we can visualise an ARPlaneAnchor and then store it's information e.g:

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

    //1. Get The Current ARPlaneAnchor
    guard let anchor = anchor as? ARPlaneAnchor else { return }

    //2. Create An SCNode & Geometry To Visualize The Plane
    let planeNode = SCNNode()
    let planeGeometry = SCNPlane(width: CGFloat(anchor.extent.x), height: CGFloat(anchor.extent.z))
    planeGeometry.firstMaterial?.diffuse.contents = UIColor.cyan
    planeNode.geometry = planeGeometry

    //3. Set The Position Based On The Anchors Extent & Rotate It
    planeNode.position = SCNVector3(anchor.center.x, anchor.center.y, anchor.center.z)
    planeNode.eulerAngles.x = -.pi / 2

    //4. Add The PlaneNode To The Node & Give It  A Unique ID
    node.addChildNode(planeNode)
    planeNode.name = String(planeID)

    //5. Store The Anchor & Node
    planesDetected[anchor] = planeNode

    //6. Increment The Plane ID
    planeID += 1

}

Now we have stored the detected planes, we then of course need to determine if any of these are in view of the ARCamera e.g:

/// Detects If An Object Is In View Of The Camera Frostrum
func detectPlaneInFrostrumOfCamera(){

    //1. Get The Current Point Of View
    if let currentPointOfView = augmentedRealityView.pointOfView{

        //2. Loop Through All The Detected Planes
        for anchorKey in planesDetected{

            let anchor = anchorKey.value

            if augmentedRealityView.isNode(anchor, insideFrustumOf: currentPointOfView){

               print("ARPlaneAnchor With ID \(anchor.name!) Is In View")

            }else{

                 print("ARPlaneAnchor With ID \(anchor.name!) Is Not In View")
            }

        }

    }
}

Finally we then need to access this function which we could do in the following delegate method for example renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval):

func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {

        detectPlaneInFrostrumOfCamera()
}

Hopefully both of these will point in the right direction...