Удалить узлы из сцены после использования ARSCNView
Я делаю приложение, используя ARKit для измерения между двумя точками. Цель состоит в том, чтобы иметь возможность измерить длину, сохранить это значение, а затем измерить ширину и сохранить.
У меня проблема с удалением узлов после того, как я получу результаты измерений.
Шаги на данный момент: 1) добавлена кнопка с функцией рестарта. это работало для сброса измерений, но не удаляло сферы со сцены, а также делало получение следующего измерения неуклюжим.
2) установить ограничение на> 2 узла. Эта функция работает лучше всего. Но снова сферы просто остаются плавающими на сцене.
Вот скриншот лучшего результата, который у меня был.
@objc func handleTap(sender: UITapGestureRecognizer) {
let tapLocation = sender.location(in: sceneView)
let hitTestResults = sceneView.hitTest(tapLocation, types: .featurePoint)
if let result = hitTestResults.first {
let position = SCNVector3.positionFrom(matrix: result.worldTransform)
let sphere = SphereNode(position: position)
sceneView.scene.rootNode.addChildNode(sphere)
let tail = nodes.last
nodes.append(sphere)
if tail != nil {
let distance = tail!.position.distance(to: sphere.position)
infoLabel.text = String(format: "Size: %.2f inches", distance)
if nodes.count > 2 {
nodes.removeAll()
}
} else {
nodes.append(sphere)
}
}
}
Я новичок в Swift (кодирование в целом), и большая часть моего кода пришла из совмещенных учебников.
2 ответа
Я думаю, что проблема в том, что вы на самом деле не удаляете SCNNodes
Вы добавили в иерархию.
Хотя вы удаляете узлы из того, что я предполагаю, является массивом SCNNodes
по телефону: nodes.removeAll()
Сначала вам нужно удалить их из иерархии сцены.
Итак, вам нужно вызвать следующую функцию на любом узле, который вы хотите удалить:
removeFromParentNode()
Который просто:
Удаляет узел из массива дочерних узлов его родителя.
Таким образом, вы должны сделать что-то вроде этого, которое сначала удаляет узлы из иерархии, а затем удаляет их из массива:
for nodeAdded in nodesArray{
nodeAdded.removeFromParentNode()
}
nodesArray.removeAll()
На основании предоставленного кода вы можете сделать следующее:
if nodes.count > 2 {
for nodeAdded in nodes{
nodeAdded.removeFromParentNode()
}
nodes.removeAll()
}
Для дальнейшего использования, если вы хотите удалить все SCNNodes
из вашей иерархии вы также можете позвонить:
self.augmentedRealityView.scene.rootNode.enumerateChildNodes { (existingNode, _) in
existingNode.removeFromParentNode()
}
При этом self.augmentedRealityView ссылается на переменную:
var augmentedRealityView: ARSCNView!
Вот очень простой рабочий пример, основанный на (и измененном из) предоставленном вами коде:
/// Places A Marker Node At The Desired Tap Point
///
/// - Parameter sender: UITapGestureRecognizer
@objc func handleTap(_ sender: UITapGestureRecognizer) {
//1. Get The Current Tap Location
let currentTapLocation = sender.location(in: sceneView)
//2. Check We Have Hit A Feature Point
guard let hitTestResult = self.augmentedRealityView.hitTest(currentTapLocation, types: .featurePoint).first else { return }
//3. Get The World Position From The HitTest Result
let worldPosition = positionFromMatrix(hitTestResult.worldTransform)
//4. Create A Marker Node
createSphereNodeAt(worldPosition)
//5. If We Have Two Nodes Then Measure The Distance
if let distance = distanceBetweenNodes(){
print("Distance == \(distance)")
}
}
/// Creates A Marker Node
///
/// - Parameter position: SCNVector3
func createSphereNodeAt(_ position: SCNVector3){
//1. If We Have More Than 2 Nodes Remove Them All From The Array & Hierachy
if nodes.count >= 2{
nodes.forEach { (nodeToRemove) in
nodeToRemove.removeFromParentNode()
}
nodes.removeAll()
}
//2. Create A Marker Node With An SCNSphereGeometry & Add It To The Scene
let markerNode = SCNNode()
let markerGeometry = SCNSphere(radius: 0.01)
markerGeometry.firstMaterial?.diffuse.contents = UIColor.cyan
markerNode.geometry = markerGeometry
markerNode.position = position
sceneView.scene.rootNode.addChildNode(markerNode)
//3. Add It To The Nodes Array
nodes.append(markerNode)
}
/// Converts A matrix_float4x4 To An SCNVector3
///
/// - Parameter matrix: matrix_float4x4
/// - Returns: SCNVector3
func positionFromMatrix(_ matrix: matrix_float4x4) -> SCNVector3{
return SCNVector3(matrix.columns.3.x, matrix.columns.3.y, matrix.columns.3.z)
}
/// Calculates The Distance Between 2 Nodes
///
/// - Returns: Float?
func distanceBetweenNodes() -> Float? {
guard let firstNode = nodes.first, let endNode = nodes.last else { return nil }
let startPoint = GLKVector3Make(firstNode.position.x, firstNode.position.y, firstNode.position.z)
let endPoint = GLKVector3Make(endNode.position.x, endNode.position.y, endNode.position.z)
let distance = GLKVector3Distance(startPoint, endPoint)
return distance
}
Пример измерительного приложения, которое может помочь вашему развитию, вы можете посмотреть здесь: Пример измерения ARKit
Надеюсь, поможет...
Это похоже на проблему логики. Вы присваивает node.last хвосту непосредственно перед проверкой, если tail не равен nil. Так что это никогда не будет!= Nil, поэтому вы никогда не будете выполнять node.append(сферу) в else.
Я согласен с @dfd. Установите точку останова, чтобы убедиться, что код выполняется перед продолжением.