我正在创建一个增强现实应用程序,该应用程序可以检测空间中的3D对象,并在它们上方弹出一个标签。当前代码使我可以检测到多个对象,但是只能弹出一种类型的标签(.sks文件)。我希望能够检测到多个对象,每个对象上方都弹出一个不同的标签。
import UIKit
import SceneKit
import ARKit
class ViewController: UIViewController, ARSCNViewDelegate {
@IBOutlet var sceneView: ARSCNView!
override func viewDidLoad() {
super.viewDidLoad()
// Set the view's delegate
sceneView.delegate = self
// Show statistics such as fps and timing information
sceneView.showsStatistics = true
// Create a new scene
let scene = SCNScene()
// Set the scene to the view
sceneView.scene = scene
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Create a session configuration
let configuration = ARWorldTrackingConfiguration()
// Object Detection
configuration.detectionObjects = ARReferenceObject.referenceObjects(inGroupNamed: "FlowerObjects", bundle: Bundle.main)!
// Run the view's session
sceneView.session.run(configuration)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Pause the view's session
//sceneView.session.pause()
}
// MARK: - ARSCNViewDelegate
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
let node = SCNNode()
if let objectAnchor = anchor as? ARObjectAnchor {
let plane = SCNPlane(width: CGFloat(objectAnchor.referenceObject.extent.x * 1.0), height: CGFloat(objectAnchor.referenceObject.extent.y * 0.7))
plane.cornerRadius = plane.width / 8
let spriteKitScene = SKScene(fileNamed: "ProductInfo")
plane.firstMaterial?.diffuse.contents = spriteKitScene
plane.firstMaterial?.isDoubleSided = true
plane.firstMaterial?.diffuse.contentsTransform = SCNMatrix4Translate(SCNMatrix4MakeScale(1, -1, 1), 0, 1, 0)
let planeNode = SCNNode(geometry: plane)
planeNode.position = SCNVector3Make(objectAnchor.referenceObject.center.x, objectAnchor.referenceObject.center.y + 0.5, objectAnchor.referenceObject.center.z) //y was 0.25
node.addChildNode(planeNode)
}
return node
}
func session(_ session: ARSession, didFailWithError error: Error) {
// Present an error message to the user
}
func sessionWasInterrupted(_ session: ARSession) {
// Inform the user that the session has been interrupted, for example, by presenting an overlay
}
func sessionInterruptionEnded(_ session: ARSession) {
// Reset tracking and/or remove existing anchors if consistent tracking is required
}
}
答案 0 :(得分:0)
ARReferenceObject
的{{1}}类型为name
的变量,简单地是:
参考对象的描述性名称。
将String
添加到ARReferenceObject
文件夹时,您可以选择设置名称(实际上会自动设置名称):
这样,您可以使用此属性名称来处理要显示的内容,具体取决于检测到的Assets.xcassett
。
就个人而言,我将使用以下委托回调来添加内容,尽管这取决于您:
ARReferenceObject
这样的工作示例可能看起来像以下内容:
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor)
所有代码均已完全注释,因此应该有意义,您会注意到我创建了一个可重用的函数来生成不同的//-------------------------
//MARK: - ARSCNViewDelegate
//-------------------------
extension ViewController: ARSCNViewDelegate{
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
/*
Check To See Whether AN ARObject Anhcor Has Been Detected
Get The The Associated ARReferenceObject
Get The Name Of The ARReferenceObject
*/
guard let objectAnchor = anchor as? ARObjectAnchor else { return }
let detectedObject = objectAnchor.referenceObject
guard let detectedObjectName = detectedObject.name else { return }
//Get The Extent & Center Of The ARReferenceObject
let detectedObjectExtent = detectedObject.extent
let detectedObjecCenter = detectedObject.center
//Log The Data
print("""
An ARReferenceObject Named \(detectedObjectName) Has Been Detected
The Extent Of The Object Is \(detectedObjectExtent)
The Center Of The Object Is \(detectedObjecCenter)
""")
//Create A Different Scene For Each Detected Object
node.addChildNode(createSKSceneForReferenceObject(detectedObject: detectedObject))
}
/// Creates A Unique SKScene Based On A Detected ARReferenceObject
///
/// - Parameter detectedObject: ARReferenceObject
/// - Returns: SCNNode
func createSKSceneForReferenceObject(detectedObject: ARReferenceObject) -> SCNNode{
let plane = SCNPlane(width: CGFloat(detectedObject.extent.x * 1.0),
height: CGFloat(detectedObject.extent.y * 0.7))
plane.cornerRadius = plane.width / 8
guard let validName = detectedObject.name else { return SCNNode() }
let spriteKitScene = SKScene(fileNamed: validName)
plane.firstMaterial?.diffuse.contents = spriteKitScene
plane.firstMaterial?.isDoubleSided = true
plane.firstMaterial?.diffuse.contentsTransform = SCNMatrix4Translate(SCNMatrix4MakeScale(1, -1, 1), 0, 1, 0)
let planeNode = SCNNode(geometry: plane)
planeNode.position = SCNVector3Make(detectedObject.center.x, detectedObject.center.y + 0.5, detectedObject.center.z)
return planeNode
}
}
,当然可以对其进行修改以添加不同的内容,例如SCNScene,SCNNode等。
我正在使用ARReferenceObject的名称加载具有相同名称的场景,但是您可以根据需要使用if / else或switch语句。
希望有帮助... 希望它能为您指明正确的方向。