Ios ARKit-如何在sceneview中获取特定节点?

Ios ARKit-如何在sceneview中获取特定节点?,ios,swift,arkit,Ios,Swift,Arkit,我是新来的。我想在sceneview中获取一个特定节点,以便与该节点交互。这是我的代码: @objc func moveNode(_ gesture: UIPanGestureRecognizer) { if !isRotating{ //1. Get The Current Touch Point let currentTouchPoint = gesture.location(in: self.sceneView) //2. Ge

我是新来的。我想在sceneview中获取一个特定节点,以便与该节点交互。这是我的代码:

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

如何在**代码块中检测哪个节点处于活动状态以进行交互?谢谢。

为了获得特定
SCNNode
的参考,您需要向我们提供一份SCNHitTest,其中:

沿指定的光线查找SCN测量对象。每人 光线和几何体之间的交点,SceneKit创建一个 点击测试结果以提供有关SCNNode对象和 包含几何图形和道路交叉点的位置 几何体的曲面

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

var nodeOne: SCNNode!
var nodeTwo: SCNNode!
并使用唯一的
名称
属性初始化:

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
    }
}
@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
   }
}
请注意,有许多不同的方法来实现您的需求,这只是其中之一。希望对你有帮助

更新:

如果您的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
    }
}
@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
   }
}

为了获得对特定
SCNNode
的引用,您需要向我们提供一份SCNHitTest,其中:

沿指定的光线查找SCN测量对象。每人 光线和几何体之间的交点,SceneKit创建一个 点击测试结果以提供有关SCNNode对象和 包含几何图形和道路交叉点的位置 几何体的曲面

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

var nodeOne: SCNNode!
var nodeTwo: SCNNode!
并使用唯一的
名称
属性初始化:

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
    }
}
@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
   }
}
请注意,有许多不同的方法来实现您的需求,这只是其中之一。希望对你有帮助

更新:

如果您的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
    }
}
@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谢谢@JOshRobbins,但是如果我有两个同名节点,会发生什么呢?你怎么能发现它?谢谢你为什么他们会有相同的名字?您可以为他们提供一个不同的节点:),因为我的情况是节点将从服务器下载,并且在服务器上具有相同的节点名称,所以我无法更改它。因此,我想检测节点而不使用名称,但我不知道如何:(我认为这是不正确的…它们可能有相同的文件名,但当您下载它时,您可以更改名称属性:)哦,它在您的更新代码中工作得很好!!非常感谢@JOshRobbins