首页 > 解决方案 > generate a specific number of SCNPlane [Swift, ARkit]

问题描述

I am beginner in swift and ARkit, and I want to generate a specific number of SCNPlane, let say 10 for example. I tried with multiple way but I only get one SCNPlane.

What do I need to do to place multiple SCNPlane in the code without any overlapping between them?

Here my code section:

//
//  MarkViewController.swift
//  Jawwab
//
//  Created by Nora Almunaif on 26/05/1440 AH.
//  Copyright © 1440 atheer. All rights reserved.
//

import UIKit
import SceneKit
import ARKit

class MarkViewController: UIViewController {

    @IBOutlet weak var sceneView: ARSCNView!



    lazy var bookNode: SCNNode = {
        let text = SCNText(string: "only for testing", extrusionDepth: 1)
        let material = SCNMaterial()
        material.diffuse.contents = UIColor.black
        text.materials = [material]

        let node = SCNNode()
        node.position = SCNVector3(0, 0, 0)
        node.scale = SCNVector3(0.0009, 0.0009, 0.0009)
        node.geometry = text



        let minVec = node.boundingBox.min
        let maxVec = node.boundingBox.max
        let bound = SCNVector3Make(maxVec.x - minVec.x,
                                   maxVec.y - minVec.y,
                                   maxVec.z - minVec.z);

        let plane = SCNPlane(width: CGFloat(bound.x + 25),
                             height: CGFloat(bound.y + 8))
        plane.cornerRadius = 5
        plane.firstMaterial?.diffuse.contents = UIColor.gray.withAlphaComponent(0.8)

        let planeNode = SCNNode(geometry: plane)
        planeNode.position = SCNVector3(CGFloat( minVec.x - 10) + CGFloat(bound.x) / 2 ,
                                        CGFloat( minVec.y) + CGFloat(bound.y) / 2,CGFloat(minVec.z - 0.01))

        node.addChildNode(planeNode)
        planeNode.name = "text"
        return node
    }()




    override func viewDidLoad() {
        super.viewDidLoad()


        self.sceneView.delegate = self as? ARSCNViewDelegate
        sceneView.showsStatistics = true

        self.configureLighting()
    }



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

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

        resetTrackingConfiguration()
    }


    func resetTrackingConfiguration() {
        guard let referenceImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil)
            else {
                print("No image detected");
                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"
    }



}
@available(iOS 12.0, *)
extension MarkViewController: 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 }
            var i=0
            while i<5 {
            let overlayNode = self.getNode(withImageName: imageName)

            let minVec = overlayNode.boundingBox.min
            let maxVec = overlayNode.boundingBox.max
            let bound = SCNVector3Make(maxVec.x - minVec.x,
                                       maxVec.y - minVec.y,
                                       maxVec.z - minVec.z);

            let plane = SCNPlane(width: CGFloat(bound.x),
                                 height: CGFloat(bound.y))
            plane.cornerRadius = 5
            plane.firstMaterial?.diffuse.contents = UIColor.gray.withAlphaComponent(0.8)

            let planeNode = SCNNode(geometry: plane)
            planeNode.position = SCNVector3(CGFloat( minVec.x - 10) + CGFloat(bound.x) / 2 ,
                                            CGFloat( minVec.y) + CGFloat(bound.y) / 2,CGFloat(minVec.z - 0.01))


            let image = UIImage(named: "flag")
            planeNode.geometry?.firstMaterial?.diffuse.contents = image


            planeNode.name = "text"

            self.sceneView.scene.rootNode.addChildNode(overlayNode)
            self.sceneView.autoenablesDefaultLighting = true
            i = i + 1
            }

        }
    }




    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
        default:
            break
        }
        return node
    }



}

And thank you

.....................................

标签: swiftarkit

解决方案


您正在调用 DidAdd Node(for:Anchor:) ,每个图像锚点只会调用一次。查看您的代码,您在完全相同的位置创建了 5 次完全相同的几何图形,因此看起来只有一个。尝试根据从 0 到 5 的 i 更改位置。

 planeNode.position = SCNVector3(CGFloat( minVec.x - 10) + CGFloat(bound.x) / 2 , CGFloat( minVec.y) + CGFloat(bound.y) + i / 2,CGFloat(minVec.z - 0.01))

飞机现在应该堆叠在一起。


推荐阅读