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

时间:2019-05-31 16:10:22

标签: swift uikit scenekit arkit

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

    }
}

1 个答案:

答案 0 :(得分:0)

ARReferenceObject的{​​{1}}类型为name的变量,简单地是:

  

参考对象的描述性名称。

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

enter image description here

这样,您可以使用此属性名称来处理要显示的内容,具体取决于检测到的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语句。

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