我对iOS Swift编程很新。我正在使用ARKit构建一个非常基本的应用程序来检测水平平面并在其上放置,平移,旋转,修改或删除对象。
我主要担心的是ARKit检测到的平面与我放置的数字对象之间的差异。我的想法是使用hitTest(:options :)选择对象(如果有的话)和hitTest(:types :)来通过点击手势选择平面。我正在附上下面的相关代码段。
@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 :)返回检测到的平面。有没有办法只选择我放置的SCNNodes(对象),而不是选择检测到的平面。我错过了什么吗?任何帮助都非常感谢。
谢谢,
Sourabh。
答案 0 :(得分:1)
要解决此问题,您应该遍历场景节点,之后您可以使用所需的节点进行操作。例如:
for node in sceneView.scene.rootNode.childNodes {
if node.name == "yorNodeName" {
// do your manipulations
}
}
不要忘记为节点添加名称。例如:
node.name = "yorNodeName"
我希望它有所帮助!
答案 1 :(得分:1)
看看你的问题,你已经到了一半。
完整处理此问题的方法是在HitTest
函数中使用以下UITapGestureRecognizer
函数:
(1)ARSCNHitTest
:
在捕获的摄像机图像中搜索与SceneKit视图中的点对应的真实世界对象或AR锚点。
(2)SCNHitTest
:
沿您指定的光线查找SCNGeometry对象。对于光线和几何体之间的每个交点,SceneKit会创建一个命中测试结果,以提供有关包含几何体的SCNNode对象和几何体表面上交点的位置的信息。
因此,以您的UITapGestureRecognizer
为例,您可以区分场景中的ARPlaneAnchor
(detectPlane)和任何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
}
}
如果您对name
的任何SCNNode
使用if let name = nodeTapped.name{
print("An SCNNode Named \(name) Has Been Tapped")
}
属性,这也会对您有所帮助,例如:
SCNNodes
此外,如果您只想检测已添加的对象,例如// View(UserControl) side:
MVVMContext context = new MVVMContext();
// make sure that the MVVMContext will be destroyed when the UserControl destroyed
context.ContainerControl = this; // your View(UserControl)
context.SetViewModel(typeof(MyViewModel), viewModel);
,那么您只需删除getureRecognizer函数的第二部分。
希望它有所帮助...