使用 ARSCNView 后从场景中删除节点
remove nodes from scene after use 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(一般编码)的新手,我的大部分代码都来自拼凑教程。
我认为这里的问题是您实际上并没有删除已添加到层次结构中的 SCNNodes
。
尽管您通过调用 nodes.removeAll()
从我假设的 SCNNodes
数组中移除节点:nodes.removeAll()
,但您首先需要从场景层次结构中实际移除它们。
所以您需要做的是在您希望删除的任何节点上调用以下函数:
removeFromParentNode()
这很简单:
Removes the node from its parent’s array of child nodes.
因此你会做这样的事情,首先从层次结构中删除节点,然后从数组中删除它们:
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
}
有关可能有助于您开发的 measuringApp 示例,您可以在此处查看:ARKit Measuring Example
希望对您有所帮助...
这看起来像是一个逻辑问题。在检查 tail 是否不为零之前,您将 nodes.last 分配给 tail 。所以它永远不会是 != nil 所以你永远不会在 else.
中执行 nodes.append(sphere)
我同意@dfd。设置断点以确保代码在继续之前正在执行。
我正在制作一个使用 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(一般编码)的新手,我的大部分代码都来自拼凑教程。
我认为这里的问题是您实际上并没有删除已添加到层次结构中的 SCNNodes
。
尽管您通过调用 nodes.removeAll()
从我假设的 SCNNodes
数组中移除节点:nodes.removeAll()
,但您首先需要从场景层次结构中实际移除它们。
所以您需要做的是在您希望删除的任何节点上调用以下函数:
removeFromParentNode()
这很简单:
Removes the node from its parent’s array of child nodes.
因此你会做这样的事情,首先从层次结构中删除节点,然后从数组中删除它们:
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
}
有关可能有助于您开发的 measuringApp 示例,您可以在此处查看:ARKit Measuring Example
希望对您有所帮助...
这看起来像是一个逻辑问题。在检查 tail 是否不为零之前,您将 nodes.last 分配给 tail 。所以它永远不会是 != nil 所以你永远不会在 else.
中执行 nodes.append(sphere)我同意@dfd。设置断点以确保代码在继续之前正在执行。