无法区分 ARKit 检测到的平面和使用 HitTest 放置的数字对象
Unable to differentiate between plane detected by ARKit and a digital object to be placed using HitTest
我对 iOS Swift 编程还很陌生。我正在使用 ARKit 构建一个非常基本的应用程序来检测水平面并在其上放置、平移、旋转、修改或删除对象。
我主要关心的是 ARKit 检测到的平面与我放置的数字对象之间的差异。我的想法是使用 hitTest(:options:) 到 select 对象(如果有的话)和 hitTest(:types:) 到 select 飞机通过点击手势。我在下面附上了相关的代码片段。
@objc func tapped(_ gesture: UITapGestureRecognizer){
let sceneView = gesture.view as! ARSCNView
let location = gesture.location(in: sceneView)
let hitTestOptions: [SCNHitTestOption: Any] = [.boundingBoxOnly: true]
let existingNodeHitTest = sceneView.hitTest(location, options: hitTestOptions)
if let existingNode = existingNodeHitTest.first?.node {
// Move, rotate, modify or delete the object
} else {
// Option to add other objects
let hitTest = sceneView.hitTest(location, types: .existingPlaneUsingExtent)
if !hitTest.isEmpty {
let node = findNode(at: location)
if node !== selectedNode {
self.addItems(hitTestResult: hitTest.first!)
}
}
}
}
func addItems(hitTestResult: ARHitTestResult) {
let scene = SCNScene(named: "BuildingModels.scnassets/model/model.scn")
let itemNode = (scene?.rootNode.childNode(withName: "SketchUp", recursively: false))!
let transform = hitTestResult.worldTransform
let position = SCNVector3(transform.columns.3.x,transform.columns.3.y,transform.columns.3.z)
itemNode.position = position
// self.sceneView.scene.lightingEnvironment.contents = scene.lightingEnvironment.contents
self.sceneView.scene.rootNode.addChildNode(itemNode)
selectedNode = itemNode
}
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
guard let planeAnchor = anchor as? ARPlaneAnchor else {return}
let gridNode = createGrid(planeAnchor: planeAnchor)
node.addChildNode(gridNode)
}
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
guard let planeAnchor = anchor as? ARPlaneAnchor else {return}
node.enumerateChildNodes { (childNode, _) in
childNode.removeFromParentNode()
}
let gridNode = createGrid(planeAnchor: planeAnchor)
node.addChildNode(gridNode)
}
当我 运行 代码时, hitTest(_:options:) returns 检测到飞机。有什么方法可以 select 只有我放置的 SCNNodes(对象)而不是检测到的平面。我错过了什么吗?非常感谢任何帮助。
谢谢,
Sourabh.
要解决此问题,您应该循环遍历场景节点,然后您可以使用您想要的节点进行操作。示例:
for node in sceneView.scene.rootNode.childNodes {
if node.name == "yorNodeName" {
// do your manipulations
}
}
不要忘记为您的节点添加名称。示例:
node.name = "yorNodeName"
希望对您有所帮助!
看看你的问题,你已经完成了一半。
完整处理此问题的方法是在 UITapGestureRecognizer
函数中使用以下 HitTest
函数:
(1) 一个 ARSCNHitTest
其中:
Searches for real-world objects or AR anchors in the captured camera image corresponding to a point in the SceneKit view.
(2) 一个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.
因此,以您的 UITapGestureRecognizer
为例,您可以像这样区分场景中的 ARPlaneAnchor
(检测到的平面)和任何 SCNNode
:
@objc func handleTap(_ gesture: UITapGestureRecognizer){
//1. Get The Current Touch Location
let currentTouchLocation = gesture.location(in: self.augmentedRealityView)
//2. Perform An ARNSCNHitTest To See If We Have Hit An ARPlaneAnchor
if let planeHitTest = augmentedRealityView.hitTest(currentTouchLocation, types: .existingPlane).first,
let planeAnchor = planeHitTest.anchor as? ARPlaneAnchor{
print("User Has Tapped On An Existing Plane = \(planeAnchor.identifier)")
return
}
//3. Perform An SCNHitTest To See If We Have Hit An SCNNode
if let nodeHitTest = augmentedRealityView.hitTest(currentTouchLocation, options: nil).first {
let nodeTapped = nodeHitTest.node
print("An SCNNode Has Been Tapped = \(nodeTapped)")
return
}
}
如果您对任何 SCNNode
使用 name
属性,这也将进一步帮助您,例如:
if let name = nodeTapped.name{
print("An SCNNode Named \(name) Has Been Tapped")
}
此外,如果您只想检测已添加的对象,例如 SCNNodes
,那么您只需删除 getureRecognizer 函数的第二部分即可。
希望对您有所帮助...
我对 iOS Swift 编程还很陌生。我正在使用 ARKit 构建一个非常基本的应用程序来检测水平面并在其上放置、平移、旋转、修改或删除对象。
我主要关心的是 ARKit 检测到的平面与我放置的数字对象之间的差异。我的想法是使用 hitTest(:options:) 到 select 对象(如果有的话)和 hitTest(:types:) 到 select 飞机通过点击手势。我在下面附上了相关的代码片段。
@objc func tapped(_ gesture: UITapGestureRecognizer){
let sceneView = gesture.view as! ARSCNView
let location = gesture.location(in: sceneView)
let hitTestOptions: [SCNHitTestOption: Any] = [.boundingBoxOnly: true]
let existingNodeHitTest = sceneView.hitTest(location, options: hitTestOptions)
if let existingNode = existingNodeHitTest.first?.node {
// Move, rotate, modify or delete the object
} else {
// Option to add other objects
let hitTest = sceneView.hitTest(location, types: .existingPlaneUsingExtent)
if !hitTest.isEmpty {
let node = findNode(at: location)
if node !== selectedNode {
self.addItems(hitTestResult: hitTest.first!)
}
}
}
}
func addItems(hitTestResult: ARHitTestResult) {
let scene = SCNScene(named: "BuildingModels.scnassets/model/model.scn")
let itemNode = (scene?.rootNode.childNode(withName: "SketchUp", recursively: false))!
let transform = hitTestResult.worldTransform
let position = SCNVector3(transform.columns.3.x,transform.columns.3.y,transform.columns.3.z)
itemNode.position = position
// self.sceneView.scene.lightingEnvironment.contents = scene.lightingEnvironment.contents
self.sceneView.scene.rootNode.addChildNode(itemNode)
selectedNode = itemNode
}
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
guard let planeAnchor = anchor as? ARPlaneAnchor else {return}
let gridNode = createGrid(planeAnchor: planeAnchor)
node.addChildNode(gridNode)
}
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
guard let planeAnchor = anchor as? ARPlaneAnchor else {return}
node.enumerateChildNodes { (childNode, _) in
childNode.removeFromParentNode()
}
let gridNode = createGrid(planeAnchor: planeAnchor)
node.addChildNode(gridNode)
}
当我 运行 代码时, hitTest(_:options:) returns 检测到飞机。有什么方法可以 select 只有我放置的 SCNNodes(对象)而不是检测到的平面。我错过了什么吗?非常感谢任何帮助。
谢谢,
Sourabh.
要解决此问题,您应该循环遍历场景节点,然后您可以使用您想要的节点进行操作。示例:
for node in sceneView.scene.rootNode.childNodes {
if node.name == "yorNodeName" {
// do your manipulations
}
}
不要忘记为您的节点添加名称。示例:
node.name = "yorNodeName"
希望对您有所帮助!
看看你的问题,你已经完成了一半。
完整处理此问题的方法是在 UITapGestureRecognizer
函数中使用以下 HitTest
函数:
(1) 一个 ARSCNHitTest
其中:
Searches for real-world objects or AR anchors in the captured camera image corresponding to a point in the SceneKit view.
(2) 一个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.
因此,以您的 UITapGestureRecognizer
为例,您可以像这样区分场景中的 ARPlaneAnchor
(检测到的平面)和任何 SCNNode
:
@objc func handleTap(_ gesture: UITapGestureRecognizer){
//1. Get The Current Touch Location
let currentTouchLocation = gesture.location(in: self.augmentedRealityView)
//2. Perform An ARNSCNHitTest To See If We Have Hit An ARPlaneAnchor
if let planeHitTest = augmentedRealityView.hitTest(currentTouchLocation, types: .existingPlane).first,
let planeAnchor = planeHitTest.anchor as? ARPlaneAnchor{
print("User Has Tapped On An Existing Plane = \(planeAnchor.identifier)")
return
}
//3. Perform An SCNHitTest To See If We Have Hit An SCNNode
if let nodeHitTest = augmentedRealityView.hitTest(currentTouchLocation, options: nil).first {
let nodeTapped = nodeHitTest.node
print("An SCNNode Has Been Tapped = \(nodeTapped)")
return
}
}
如果您对任何 SCNNode
使用 name
属性,这也将进一步帮助您,例如:
if let name = nodeTapped.name{
print("An SCNNode Named \(name) Has Been Tapped")
}
此外,如果您只想检测已添加的对象,例如 SCNNodes
,那么您只需删除 getureRecognizer 函数的第二部分即可。
希望对您有所帮助...