简体   繁体   中英

ARKit - How to get the specific node in sceneview?

I'm new in ARKit. I want to get a specific node in sceneview to interactive with that node. This is my code:

@objc func moveNode(_ gesture: UIPanGestureRecognizer) {

    if !isRotating{

        //1. Get The Current Touch Point
        let currentTouchPoint = gesture.location(in: self.sceneView)

        //2. Get The Next Feature Point Etc
        guard let hitTest = self.sceneView.hitTest(currentTouchPoint, types: .existingPlane).first else { return }

        //3. Convert To World Coordinates
        let worldTransform = hitTest.worldTransform

        //4. Set The New Position
        let newPosition = SCNVector3(worldTransform.columns.3.x, worldTransform.columns.3.y, worldTransform.columns.3.z)

        //5. Apply To The Node
        self.sceneView.scene.rootNode.enumerateChildNodes{ (node, _) in
            //**********************************************************
            // how to detect which node is active to interactive here???
            node.simdPosition = float3(newPosition.x, newPosition.y, newPosition.z)
            //**********************************************************
        }
    }
}

How to detect which node is active to interactive in ** code block? Thank you.

In order to get a reference to a specific SCNNode you need to make us of an SCNHitTest which:

Looks for SCNGeometry objects along the ray you specify. For each intersection between the ray and and a geometry, SceneKit creates a hit-test result to provide information about both the SCNNode object containing the geometry and the location of the intersection on the geometry's surface.

Lets assume therefore that in your scene you have two SCNode variables eg:

var nodeOne: SCNNode!
var nodeTwo: SCNNode!

And that these are initialised with a unique name property:

let nodeOneGeometry = SCNSphere(radius: 0.2)
nodeOneGeometry.firstMaterial?.diffuse.contents = UIColor.cyan
nodeOne = SCNNode(geometry: nodeOneGeometry)
nodeOne.name = "Node One"
nodeOne.position = SCNVector3(0, 0, -1.5)
augmentedRealityView.scene.rootNode.addChildNode(nodeOne)

let nodeTwoGeometry = SCNBox(width: 0.2, height: 0.2, length: 0.2, chamferRadius: 0)
nodeTwoGeometry.firstMaterial?.diffuse.contents = UIColor.cyan
nodeTwo = SCNNode(geometry: nodeTwoGeometry)
nodeTwo.name = "Node Two"
nodeTwo.position = SCNVector3(0.5, 0, -1.5)
augmentedRealityView.scene.rootNode.addChildNode(nodeTwo)

We also need to create another variable to store the current node eg:

var currentNode: SCNNode?

Which we will use in your existing function like so:

@objc func moveNode(_ gesture: UIPanGestureRecognizer) {

    //1. Get The Current Touch Point
    let currentTouchPoint = gesture.location(in: self.augmentedRealityView)

    //2. If The Gesture State Has Begun Perform A Hit Test To Get The SCNNode At The Touch Location
    if gesture.state == .began{

        //2a. Perform An SCNHitTest To Detect If An SCNNode Has Been Touched
        guard let nodeHitTest = self.augmentedRealityView.hitTest(currentTouchPoint, options: nil).first else { return }

        //2b. Get The SCNNode Result
        let nodeHit = nodeHitTest.node

        //2c. Get The Namt Of The Node & Set As The Current Node
        if let nodeName = nodeHit.name{

            if nodeName == "Node One"{

                print("Node One Hit")
                currentNode = nodeHit

            }else if nodeName == "Node Two"{

                print("Node Two Hit")
                currentNode = nodeHit

            }else{
                return
            }
        }
    }

    //3. If The Gesture State Has Changed Then Perform An ARSCNHitTest To Detect Any Existing Planes
    if gesture.state == .changed{

        //3b. Get The Next Feature Point Etc
        guard let hitTest = self.augmentedRealityView.hitTest(currentTouchPoint, types: .existingPlane).first else { return }

        //3c. Convert To World Coordinates
        let worldTransform = hitTest.worldTransform

        //3d. Set The New Position
        let newPosition = SCNVector3(worldTransform.columns.3.x, worldTransform.columns.3.y, worldTransform.columns.3.z)

        //3e. Apply To The Node
        currentNode?.simdPosition = float3(newPosition.x, newPosition.y, newPosition.z)

    }

    //4. If The Gesture State Has Ended Remove The Reference To The Current Node
    if gesture.state == .ended{
        currentNode = nil
    }
}

Please note that there are many different ways to achieve what you need, and that this is just one of them. Hope it helps...

Update:

If you don't have a name for your SCNNode or perhaps they have the same name (don't see why they would though) you can simply modify the function like so:

@objc func moveNode(_ gesture: UIPanGestureRecognizer) {

//1. Get The Current Touch Point
let currentTouchPoint = gesture.location(in: self.augmentedRealityView)

//2. If The Gesture State Has Begun Perform A Hit Test To Get The SCNNode At The Touch Location
if gesture.state == .began{

    //2a. Perform An SCNHitTest To Detect If An SCNNode Has Been Touched
    guard let nodeHitTest = self.augmentedRealityView.hitTest(currentTouchPoint, options: nil).first else { return }

    //2b. Get The SCNNode Result
    let nodeHit = nodeHitTest.node

    //2c. Set As The Current Node
    currentNode = nodeHit

}

//3. If The Gesture State Has Changed Then Perform An ARSCNHitTest To Detect Any Existing Planes
if gesture.state == .changed{

    //3b. Get The Next Feature Point Etc
    guard let hitTest = self.augmentedRealityView.hitTest(currentTouchPoint, types: .existingPlane).first else { return }

    //3c. Convert To World Coordinates
    let worldTransform = hitTest.worldTransform

    //3d. Set The New Position
    let newPosition = SCNVector3(worldTransform.columns.3.x, worldTransform.columns.3.y, worldTransform.columns.3.z)

    //3e. Apply To The Node
    currentNode?.simdPosition = float3(newPosition.x, newPosition.y, newPosition.z)

}

//4. If The Gesture State Has Ended Remove The Reference To The Current Node
if gesture.state == .ended{
    currentNode = nil
   }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM