Как я могу преобразовать код ниже, чтобы позволить мне сканировать несколько объектов с разными файлами .sks для каждого? - PullRequest
0 голосов
/ 31 мая 2019

Я создаю приложение дополненной реальности, которое обнаруживает трехмерные объекты в космосе и над ними появляется метка.Текущий код позволяет мне обнаруживать несколько объектов, но позволяет всплывать только меткам одного типа (файл .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 голосов
/ 01 июня 2019

ARReferenceObject имеет переменную name типа String, которая просто:

Описательное имя для ссылочного объекта.

Когда вы добавляете ARReferenceObject в папку Assets.xcassett s, у вас есть возможность установить имя (которое на самом деле устанавливается автоматически):

enter image description here

Таким образом, вы можете использовать это имя свойства для обработки того, что показывать в зависимости от обнаруженного 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, которые, конечно, могут быть изменены для добавления другого контента, например, SCNСцены, SCNNode и т. Д.

Я использую имя ARReferenceObject для загрузки сцены с тем же именем, но вы можете использовать оператор if / else или switch в зависимости от того, что вам нужно.

Надеюсь, это поможет ... Надеюсь, это направит вас в правильном направлении.

...