ARKit - 如何获取场景视图中的特定节点?
ARKit - How to get the specific node in sceneview?
我是 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)
//**********************************************************
}
}
}
如何在**代码块中检测哪个节点处于活动交互状态?谢谢。
为了获得对特定 SCNNode
的引用,您需要为我们创建一个 SCNHitTest,其中:
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.
因此我们假设在您的场景中您有两个 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
}
}
我是 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)
//**********************************************************
}
}
}
如何在**代码块中检测哪个节点处于活动交互状态?谢谢。
为了获得对特定 SCNNode
的引用,您需要为我们创建一个 SCNHitTest,其中:
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.
因此我们假设在您的场景中您有两个 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
}
}