Как обнаружить 2D-изображение с помощью ARKit и RealityKit?

Я хочу обнаружить 2D-изображение с помощью ARKit и RealityKit. Я не хочу использовать SceneKit, поскольку многие реализации основаны на RealityKit (доступ к Experience.rcproject). Есть идеи?

Я пробовал этот код

import ARKit
import RealityKit


class ViewController: UIViewController, ARSessionDelegate {

    func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {

        guard let imageAnchor = anchors.first as? ARImageAnchor,
              let _ = imageAnchor.referenceImage.name
        else { return }

        let anchor = AnchorEntity(anchor: imageAnchor)

        // Add Model Entity to anchor
        anchor.addChild(model)

        arView.scene.anchors.append(anchor)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        arView.session.delegate = self
        resetTrackingConfig()
    }

    func resetTrackingConfig() {

        guard let refImg = ARReferenceImage.referenceImages(inGroupNamed: "Sub",
                                                                  bundle: nil)
        else { return }

        let config = ARWorldTrackingConfiguration()
        config.detectionImages = refImg
        config.maximumNumberOfTrackedImages = 1

        let options = [ARSession.RunOptions.removeExistingAnchors,
                       ARSession.RunOptions.resetTracking]

        arView.session.run(config, options: ARSession.RunOptions(options))
    }
}

Из предыдущего поста, но он кажется устаревшим / неполным. Приведенный ниже код работает для SceneKit, но я не могу получить доступ к сценам из Experience.rcproject.

import UIKit
import RealityKit
import SceneKit
import ARKit

class ViewController: UIViewController, ARSCNViewDelegate {

    @IBOutlet var sceneView: ARSCNView!

    override func viewDidLoad() {
        super.viewDidLoad()
        sceneView.delegate = self
    }

    override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)

            let configuration = ARImageTrackingConfiguration()

            guard let trackedImages = ARReferenceImage.referenceImages(inGroupNamed: "Photos", bundle: Bundle.main) else {
                print("No images available")
                return
            }

            configuration.trackingImages = trackedImages
            configuration.maximumNumberOfTrackedImages = 7

            sceneView.session.run(configuration)
        }

    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
        <#code#>
    }

        func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {

            let node = SCNNode()

            if let imageAnchor = anchor as? ARImageAnchor {
                let plane = SCNPlane(width: imageAnchor.referenceImage.physicalSize.width, height: imageAnchor.referenceImage.physicalSize.height)

                plane.firstMaterial?.diffuse.contents = UIColor(white: 1, alpha: 0.8)

                let planeNode = SCNNode(geometry: plane)
                planeNode.eulerAngles.x = -.pi / 2

                let shipScene = SCNScene(named: "ship.scn")!
                let shipNode = shipScene.rootNode.childNodes.first!

                shipNode.position = SCNVector3Zero
                shipNode.position.z = 0.15

                planeNode.addChildNode(shipNode)

                node.addChildNode(planeNode)
            }
            return node
        }
}

2 ответа

В качестве альтернативы включению эталонных изображений в ваш пакет добавьте свои изображения - во время выполнения, если хотите - например:

а. Настройте словарь, чтобы помочь связать изображения с якорями:

private var imageAnchorToEntity: [ARImageAnchor: AnchorEntity] = [:]

б. Установите эталонные изображения вviewDidLoad() или в любом другом месте по вашему выбору:

let exampleImage = ARReferenceImage(UIImage(named: "example"), orientation: .up, physicalWidth: 0.2)
let set = Set<ARReferenceImage>()
set.insert(exampleImage) 
let config = ARImageTrackingConfiguration()
config.trackingImages = set

c. В методе делегата, который вызывается после добавления ARAnchor с помощью ARKit, определите привязку как ARImageAnchor, создайте из него AnchorEntity и свяжите его с ARImageAnchor для использования в будущем при помощи словаря:

func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
    anchors.compactMap { $0 as? ARImageAnchor }.forEach {
        let anchorEntity = AnchorEntity(anchor: $0)
        // Add other entities as children to your AnchorEntity
        anchorEntity.addChild(yourEntity)
        imageAnchorToEntity[$0] = anchorEntity // Setting the reference
        arView.scene.addAnchor(anchorEntity)
}

d. Соответственно, вы можете получить ссылку на свой AnchorEntity и его дочерние элементы в методе делегата сеанса (_:didUpdate:), открыв свой словарь:

func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
    anchors.compactMap { $0 as? ARImageAnchor }.forEach {
        let anchorEntity = imageAnchorToEntity[$0]
        anchorEntity?.transform.matrix = $0.transform
    }
}

Примечание: я использовал ARImageTrackingConfigurationв данном случае, который используется в основном для отслеживания изображений. Он работает наARWorldTrackingConfiguration также, но ARKit может не отслеживать ваши изображения, а пользователь перемещает устройство.

  1. Добавьте новую "группу ресурсов AR" к ресурсам вашего проекта и добавьте туда свое изображение маркера. Обязательно укажите ширину и высоту. Я назвал группу "Маркеры".
  2. Добавьте следующий код (у меня он есть в viewWillAppear) моего UIViewController:
    let imageAnchor = AnchorEntity(.image(group: "Markers", name: "YourImageName"))
    yourARView.scene.anchors.append(imageAnchor)
    // Setup some models to add etc
    imageAnchor.addChild(someModel)
Другие вопросы по тегам