我如何转换下面的代码,让我扫描多个对象,每个对象都有不同的 .sks 文件?

How can I convert the code below to let me scan in multiple objects with different .sks files for each?

我正在创建一个增强现实应用程序,用于检测 space 中的 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

    }
}

一个 ARReferenceObject 有一个 name 类型的 String 变量,它很简单:

A descriptive name for the reference object.

当您将 ARReferenceObject 添加到 Assets.xcassetts 文件夹时,您可以选择设置名称(实际上会自动设置):

因此,您可以使用此 属性 名称来处理根据检测到的 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
  }
}

所有代码都有完整的注释,所以它应该是有意义的,你会注意到我创建了一个可重用的函数来生成不同的 SKScenes,当然可以修改它以添加不同的内容,例如SCNScene、SCNNodes 等

我正在使用 ARReferenceObject 的名称来加载同名场景,但您可以根据需要使用 if/else 或 switch 语句。

希望对您有所帮助... 希望它能为您指明正确的方向。