【问题标题】:ARKit - How to get the specific node in sceneview?ARKit - 如何在场景视图中获取特定节点?
【发布时间】:2018-03-31 13:40:08
【问题描述】:

我是 ARKit 的新手。我想在场景视图中获取特定节点以与该节点交互。这是我的代码:

@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)
            //**********************************************************
        }
    }
}

如何检测**代码块中哪个节点是活跃的交互?谢谢。

【问题讨论】:

    标签: ios swift arkit


    【解决方案1】:

    为了获得对特定 SCNNode 的引用,您需要为我们创建一个 SCNHitTest,它:

    沿您指定的射线查找 SCNGeometry 对象。对于每个 射线和几何之间的交集,SceneKit 创建了一个 hit-test 结果提供有关 SCNNode 对象的信息 包含几何图形和交点的位置 几何体的表面。

    因此假设在您的场景中有两个 SCNode 变量,例如:

    var nodeOne: SCNNode!
    var nodeTwo: SCNNode!
    

    并且这些是用唯一的name 属性初始化的:

    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)
    

    我们还需要创建另一个变量来存储当前节点例如:

    var currentNode: SCNNode?
    

    我们将在您现有的函数中使用如下:

    @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
        }
    }
    

    请注意,有许多不同的方法可以满足您的需求,这只是其中一种。希望对你有帮助...

    更新:

    如果您的 SCNNode 没有名称,或者它们可能具有相同的名称(不明白为什么会这样),您可以像这样简单地修改函数:

    @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
       }
    }
    

    【讨论】:

    • 感谢@JoshRobbins,但是如果我有两个同名节点会怎样?怎么能检测出来?谢谢
    • 为什么他们会有相同的名字?你可以只为他们提供一个不同的:)
    • 因为我的情况是节点将从服务器下载,并且它在服务器上具有相同的节点名称,所以我无法更改它。所以我想在不使用名称的情况下检测节点,但我不知道如何:(
    • 我认为这不正确...它们可能具有相同的文件名,但是当您下载它时,您可以更改名称属性:)
    • 哦,它在您的更新代码中运行完美!非常感谢@JOshRobbins
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-16
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-19
    相关资源
    最近更新 更多