Использование нескольких AR Image Anchors для отображения динамического 3D наложения

Я работаю над проектом, в котором мы должны определить определенное количество пользовательских QR-кодов (например, ARImageAnchors), а затем использовать положение этих якорей для динамического отображения трехмерного наложения. Чтобы быть точным, мы планируем динамически отображать трехмерную модель анатомии человека над якорями, которые будут размещены на манекене. Например, манекен, на который мы помещаем QR-коды, меньше или больше размера 3D-модели по умолчанию, мы хотели бы адаптировать его в зависимости от расстояния между изображениями. Ниже приведен пример кода, от которого я думаю работать (источник: https://www.appcoda.com/arkit-image-recognition/).

import UIKit
import ARKit

class ViewController: UIViewController {

@IBOutlet weak var sceneView: ARSCNView!
@IBOutlet weak var label: UILabel!

let fadeDuration: TimeInterval = 0.3
let rotateDuration: TimeInterval = 3
let waitDuration: TimeInterval = 0.5

lazy var fadeAndSpinAction: SCNAction = {
    return .sequence([
        .fadeIn(duration: fadeDuration),
        .rotateBy(x: 0, y: 0, z: CGFloat.pi * 360 / 180, duration: rotateDuration),
        .wait(duration: waitDuration),
        .fadeOut(duration: fadeDuration)
        ])
}()

lazy var fadeAction: SCNAction = {
    return .sequence([
        .fadeOpacity(by: 0.8, duration: fadeDuration),
        .wait(duration: waitDuration),
        .fadeOut(duration: fadeDuration)
        ])
}()

lazy var treeNode: SCNNode = {
    guard let scene = SCNScene(named: "tree.scn"),
        let node = scene.rootNode.childNode(withName: "tree", recursively: false) else { return SCNNode() }
    let scaleFactor = 0.005
    node.scale = SCNVector3(scaleFactor, scaleFactor, scaleFactor)
    node.eulerAngles.x = -.pi / 2
    return node
}()

lazy var bookNode: SCNNode = {
    guard let scene = SCNScene(named: "book.scn"),
        let node = scene.rootNode.childNode(withName: "book", recursively: false) else { return SCNNode() }
    let scaleFactor  = 0.1
    node.scale = SCNVector3(scaleFactor, scaleFactor, scaleFactor)
    return node
}()

lazy var mountainNode: SCNNode = {
    guard let scene = SCNScene(named: "mountain.scn"),
        let node = scene.rootNode.childNode(withName: "mountain", recursively: false) else { return SCNNode() }
    let scaleFactor  = 0.25
    node.scale = SCNVector3(scaleFactor, scaleFactor, scaleFactor)
    node.eulerAngles.x += -.pi / 2
    return node
}()

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

func configureLighting() {
    sceneView.autoenablesDefaultLighting = true
    sceneView.automaticallyUpdatesLighting = true
}

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

    resetTrackingConfiguration()
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    sceneView.session.pause()
}

@IBAction func resetButtonDidTouch(_ sender: UIBarButtonItem) {
    resetTrackingConfiguration()
}

func resetTrackingConfiguration() {
    guard let referenceImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil) else { return }
    let configuration = ARWorldTrackingConfiguration()
    configuration.detectionImages = referenceImages
    let options: ARSession.RunOptions = [.resetTracking, .removeExistingAnchors]
    sceneView.session.run(configuration, options: options)
    label.text = "Move camera around to detect images"
}
}

extension ViewController: ARSCNViewDelegate {

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    DispatchQueue.main.async {
        guard let imageAnchor = anchor as? ARImageAnchor,
            let imageName = imageAnchor.referenceImage.name else { return }

        // TODO: Comment out code
        //            let planeNode = self.getPlaneNode(withReferenceImage: imageAnchor.referenceImage)
        //            planeNode.opacity = 0.0
        //            planeNode.eulerAngles.x = -.pi / 2
        //            planeNode.runAction(self.fadeAction)
        //            node.addChildNode(planeNode)

        // TODO: Overlay 3D Object
        let overlayNode = self.getNode(withImageName: imageName)
        overlayNode.opacity = 0
        overlayNode.position.y = 0.2
        overlayNode.runAction(self.fadeAndSpinAction)
        node.addChildNode(overlayNode)

        self.label.text = "Image detected: \"\(imageName)\""
    }
}

func getPlaneNode(withReferenceImage image: ARReferenceImage) -> SCNNode {
    let plane = SCNPlane(width: image.physicalSize.width,
                         height: image.physicalSize.height)
    let node = SCNNode(geometry: plane)
    return node
}

func getNode(withImageName name: String) -> SCNNode {
    var node = SCNNode()
    switch name {
    case "Book":
        node = bookNode
    case "Snow Mountain":
        node = mountainNode
    case "Trees In the Dark":
        node = treeNode
    default:
        break
    }
    return node
}

}

Я знаю, что 3D-оверлей отображается в функции рендерера выше, но он отображается только поверх одного обнаруженного якоря изображения. Теперь мой вопрос : можно ли ссылаться на несколько якорей ARImage для динамического отображения одной трехмерной модели?

Будучи новичком в ARKit и Swift в целом, я пока не знаю, как решить эту проблему. Я надеюсь, что кто-то может иметь представление о том, как обойти это и указать мне правильное направление. Любая помощь будет оценена!

Заранее спасибо!

0 ответов

Другие вопросы по тегам