AR参考图像平面在iOS Swift中位置不正确?

时间:2022-07-25 11:52:49

I am working on business card profile information using ar reference image. When reference detects it will show company ceo details, address, photo and team members information, etc. Initially image detected it plane will move to right using runAction amintion.

我正在使用ar参考图像处理名片档案信息。当参考检测到它将显示公司首席执行官详细信息,地址,照片和团队成员信息等。最初检测到图像,它将使用runAction amintion向右移动。

My question is detected ar refrence, plane position was stable and its moving here and there. How to fit plane position with ar reference image.

我的问题是检测到的,飞机位置稳定,它在这里和那里移动。如何使用参考图像拟合平面位置。

Here is the screenshot my result:[![enter image description here][1]][1]

这是我的结果截图:[![在此输入图像描述] [1]] [1]

Here is the code i used:

这是我使用的代码:

var weboverlayview: CALayer?
var loadWeb: UIWebView?
override func viewDidLoad() {
    super.viewDidLoad()

    // Set the view's delegate
    sceneView.delegate = self

    // Show statistics such as fps and timing information
    sceneView.showsStatistics = true
    sceneView.autoenablesDefaultLighting = true
    let ARScene = SCNScene()
    sceneView.scene = ARScene

}

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

    // Create a session configuration
    let configuration = ARWorldTrackingConfiguration()
    configuration.planeDetection = [.vertical, .horizontal]
    configuration.detectionImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil)
    // 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()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Release any cached data, images, etc that aren't in use.
}


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

    let anchorNode = SCNNode()
    anchorNode.name = "anchor"
    sceneView.scene.rootNode.addChildNode(anchorNode)
    return anchorNode

}

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {

    var labelNode:SCNNode?
    var companyLabelNode: SCNNode?
    var addressLabelNode: SCNNode?
    var webaddressLabelNode: SCNNode?
    var maillabelNode: SCNNode?
    var mobileLabelNode:SCNNode?
    var teamLabelNode:SCNNode?


    guard let imageAnchor = anchor as? ARImageAnchor else {return}
    if let imageName  = imageAnchor.referenceImage.name {

        print(imageName)



        if imageName == "card"{



            let plane = SCNPlane(width: 20,height: 24)
            plane.firstMaterial?.diffuse.contents = UIColor.black.withAlphaComponent(0.75)
            plane.cornerRadius = 0.25

            let planeNodee = SCNNode(geometry: plane)
            planeNodee.eulerAngles.x = -.pi / 2
            planeNodee.runAction(SCNAction.moveBy(x: -5, y: 0, z: 19, duration: 0.75))

            labelNode = self.addLabel(text: "Gowdhaman Kandasamy \nFounder and CEO", anchor: imageAnchor)
            labelNode?.runAction(SCNAction.moveBy(x: -1.3, y: 1, z: 16.8, duration: 0.75))



            companyLabelNode = self.addLabel(text: "CZ Smart Mobility", anchor: imageAnchor)
            companyLabelNode?.runAction(SCNAction.moveBy(x: 1.5, y: 1, z: 22, duration: 0.75))

            addressLabelNode = self.addAddressLabel(text: "Official Address:\n\n1st floor, TBI Office,\nDr.col JEPPIAR Research Park,\nResearch and development center,\nSathyabama University,\nChennai-600119\nTamil nadu, India.", anchor: imageAnchor)
            addressLabelNode?.runAction(SCNAction.moveBy(x: -4.8, y: 1, z: 16.8, duration: 0.75))



            let userImagePlane = SCNPlane(width: 3.5, height: 3.5)
            userImagePlane.firstMaterial?.diffuse.contents = UIImage(named: "gow")
            userImagePlane.cornerRadius = 0.25
            let userPlaneNode = SCNNode(geometry: userImagePlane)
            userPlaneNode.eulerAngles.x = -.pi/2
            userPlaneNode.runAction(SCNAction.moveBy(x: -1, y: 1, z: 9.5, duration: 0.75))


            let webImagePlane = SCNPlane(width: 1, height: 1)
            webImagePlane.firstMaterial?.diffuse.contents = UIImage(named: "web")

            webImagePlane.cornerRadius = 0.25
            let webPlanenode = SCNNode(geometry: webImagePlane)
            webPlanenode.eulerAngles.x = -.pi/2
            webPlanenode.runAction(SCNAction.moveBy(x: -7, y: 1, z: 12.5, duration: 0.75))
            webaddressLabelNode = addAddressLabel(text: "www.czsm.co.in", anchor: imageAnchor)
            webaddressLabelNode?.runAction(SCNAction.moveBy(x: -8.7, y: 1, z: 18.2, duration: 0.75))

            let mailImagePlane = SCNPlane(width: 1, height: 1)
            mailImagePlane.firstMaterial?.diffuse.contents = UIImage(named: "mail")

            mailImagePlane.cornerRadius = 0.25
            let mailPlanenode = SCNNode(geometry: mailImagePlane)
            mailPlanenode.eulerAngles.x = -.pi/2
            mailPlanenode.runAction(SCNAction.moveBy(x: -7, y: 1, z: 17.5, duration: 0.75))
            maillabelNode = addAddressLabel(text: "gowdhaman@czsm.co.in", anchor: imageAnchor)
            maillabelNode?.runAction(SCNAction.moveBy(x: -8.7, y: 1, z: 23.2, duration: 0.75))

            let mobileImagePlane = SCNPlane(width: 1, height: 1)
            mobileImagePlane.firstMaterial?.diffuse.contents = UIImage(named: "mobile")

            mobileImagePlane.cornerRadius = 0.25
            let mobilePlanenode = SCNNode(geometry: mobileImagePlane)
            mobilePlanenode.eulerAngles.x = -.pi/2
            mobilePlanenode.runAction(SCNAction.moveBy(x: -7, y: 1, z: 23.9, duration: 0.75))
            mobileLabelNode = addAddressLabel(text: "+919941123110", anchor: imageAnchor)
            mobileLabelNode?.runAction(SCNAction.moveBy(x: -8.7, y: 1, z: 29.7, duration: 0.75))


            /************Team members*************/

            teamLabelNode = self.addLabel(text: "Team Members", anchor: imageAnchor)
            teamLabelNode?.runAction(SCNAction.moveBy(x: -9.8, y: 1, z: 22, duration: 0.75))


            let sivaImagePlane = SCNPlane(width: 2.7, height: 2.7)
            sivaImagePlane.firstMaterial?.diffuse.contents = UIImage(named: "pic2")

            sivaImagePlane.cornerRadius = 0.25
            let sivaPlanenode = SCNNode(geometry: sivaImagePlane)
            sivaPlanenode.eulerAngles.x = -.pi/2
            sivaPlanenode.runAction(SCNAction.moveBy(x: -11, y: 1, z: 9.5, duration: 0.75))


            let parameshImagePlane = SCNPlane(width: 2.7, height: 2.7)
            parameshImagePlane.firstMaterial?.diffuse.contents = UIImage(named: "pic4")

            parameshImagePlane.cornerRadius = 0.25
            let parameshPlanenode = SCNNode(geometry: parameshImagePlane)
            parameshPlanenode.eulerAngles.x = -.pi/2
            parameshPlanenode.runAction(SCNAction.moveBy(x: -11, y: 1, z: 9.5, duration: 0.75))






            node.addChildNode(planeNodee)
            node.addChildNode(labelNode!)
            node.addChildNode(companyLabelNode!)
            node.addChildNode(userPlaneNode)
            node.addChildNode(addressLabelNode!)
            node.addChildNode(webPlanenode)
            node.addChildNode(webaddressLabelNode!)
            node.addChildNode(mailPlanenode)
            node.addChildNode(maillabelNode!)
            node.addChildNode(mobilePlanenode)
            node.addChildNode(mobileLabelNode!)
            node.addChildNode(teamLabelNode!)

            node.addChildNode(sivaPlanenode)
            node.addChildNode(parameshPlanenode)


       //                node.addChildNode(czwebPlaneNode)
            self.sceneView.scene.rootNode.addChildNode(node)



        }

    }


   }
   func webButton() {






  }


func addLabel(text: String, anchor: ARImageAnchor) -> SCNNode {
    let plane = SCNPlane(width: 10,
                         height: 4)

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



    let skScene = SKScene(size: CGSize(width: 400, height: 100))

    skScene.backgroundColor = UIColor.clear

    let substrings: [String] = text.components(separatedBy: "\n")
    for aSubstring in substrings {
        let lbl = SKLabelNode(text: aSubstring)
        lbl.fontSize = 18
        lbl.numberOfLines = 1
        lbl.fontColor = UIColor.white
        lbl.fontName = "Avenir-medium"
        let y = CGFloat(substrings.index(of: aSubstring)! + 1) * lbl.fontSize
        print("yname::::\(y)")
        lbl.position = CGPoint(x: 0, y: y)
        lbl.horizontalAlignmentMode = .left
        lbl.yScale *= -1
        skScene.addChild(lbl)



    }




    let material = SCNMaterial()
    material.isDoubleSided = false
    material.diffuse.contents = skScene
    plane.materials = [material]

    return planeNode
    }

      func addCompanyLabel(text: String, anchor: ARImageAnchor) -> SCNNode {
        let plane1 = SCNPlane(width: 10,
                         height: 4)

    let planeNode1 = SCNNode(geometry: plane1)
    planeNode1.eulerAngles.x = (-.pi)/2
    planeNode1.eulerAngles.y = (-.pi)/2
    //        planeNode.eulerAngles.z = (-.pi)/2



    let skScene1 = SKScene(size: CGSize(width: 400, height: 100))

    skScene1.backgroundColor = UIColor.clear

    let substrings: [String] = text.components(separatedBy: "\n")
    for aSubstring in substrings {
        let lbl1 = SKLabelNode(text: aSubstring)
        lbl1.fontSize = 20
        lbl1.numberOfLines = 1
        lbl1.fontColor = UIColor.white
        lbl1.fontName = "Avenir-medium"
        let y = CGFloat(substrings.index(of: aSubstring)! + 1) * lbl1.fontSize
        print("ycompanname::::\(y)")
        lbl1.position = CGPoint(x: 0, y: y)
        lbl1.horizontalAlignmentMode = .left
        lbl1.yScale *= -1
        skScene1.addChild(lbl1)



    }

    let material = SCNMaterial()
    material.isDoubleSided = false
    material.diffuse.contents = skScene1
    plane1.materials = [material]

       return planeNode1
     }

    func addAddressLabel(text: String, anchor: ARImageAnchor) -> SCNNode {
    let plane = SCNPlane(width: 10,
                         height: 4)

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



    let skScene = SKScene(size: CGSize(width: 500, height: 200))

    skScene.backgroundColor = UIColor.clear

    let substrings: [String] = text.components(separatedBy: "\n")
    for aSubstring in substrings {
        let lbl = SKLabelNode(text: aSubstring)
        lbl.fontSize = 20
     //            lbl.numberOfLines = 1
        lbl.fontColor = UIColor.white
        lbl.fontName = "Avenir-medium"
        let y = CGFloat(substrings.index(of: aSubstring)! + 1) * lbl.fontSize
        print("yaddress::::\(y)")
        lbl.position = CGPoint(x: 0, y: y)
        lbl.horizontalAlignmentMode = .left
        lbl.yScale *= -1
        skScene.addChild(lbl)



    }

    let material = SCNMaterial()
    material.isDoubleSided = false
    material.diffuse.contents = skScene
    plane.materials = [material]

    return planeNode
   }




     func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {


  //        guard let planeAnchor = anchor as? ARPlaneAnchor else {return}
  //        let planeGeometry = planeAnchor.geometry
   //        guard let device = MTLCreateSystemDefaultDevice() else {return}
  //        let plane  = ARSCNPlaneGeometry(device: device)
   //        plane?.update(from: planeGeometry)
    //        node.geometry = plane
    //        node.geometry?.firstMaterial?.diffuse.contents = UIColor.black
   //        node.geometry?.firstMaterial?.transparency = 1
  //        node.geometry?.firstMaterial?.fillMode = SCNFillMode.lines

     }



  }

Excepted result like this ar reference plane will fit to card https://www.facebook.com/oscarfalmer/videos/10156651667309345/

像这个ar参考平面的例外结果适合卡https://www.facebook.com/oscarfalmer/videos/10156651667309345/

2 个解决方案

#1


6  

The first thing you need to consider is whether you want to use ARWorldTrackingConfiguration or ARImageTrackingConfiguration (IOS12).

您需要考虑的第一件事是您是否要使用ARWorldTrackingConfiguration或ARImageTrackingConfiguration(IOS12)。

If you use ARImageTrackingConfiguration, you cant make use of PlaneDetection, as this is an Image Only tracking configuration:

如果您使用ARImageTrackingConfiguration,则无法使用PlaneDetection,因为这是一个Image Only跟踪配置:

which lets you anchor virtual content to known images only when those images are in view of the camera. World tracking with image detection lets you use known images to add virtual content to the 3D world, and continues to track the position of that content in world space even after the image is no longer in view.

只有当这些图像在相机视野中时,才能将虚拟内容锚定到已知图像。通过图像检测进行世界跟踪,您可以使用已知图像将虚拟内容添加到3D世界,并在图像不再可见时继续跟踪该内容在世界空间中的位置。

This would be your best bet, if you want your content to stay anchored to the image at all times (when in view of the camera) since:

如果您希望您的内容始终保持固定在图像上(在相机视野中),这将是您最好的选择,因为:

it tracks their movement with six degrees of freedom (6DOF): specifically, the three rotation axes (roll, pitch, and yaw), and three translation axes (movement in x, y, and z).

它以六个*度(6DOF)跟踪它们的运动:具体地说,三个旋转轴(滚动,俯仰和偏转)和三个平移轴(在x,y和z中的运动)。

On the other hand if you want to detect ARPlaneAnchors, as well as ARImageAnchors, but aren't bothered that any content associated with your ARImageAnchor won't track constantly then you should use ARWorldTrackingConfiguration.

另一方面,如果你想检测ARPlaneAnchors以及ARImageAnchors,但是不要担心任何与你的ARImageAnchor相关的内容不会不断跟踪,那么你应该使用ARWorldTrackingConfiguration。

As @Trinca also said you need to ensure that the measurements you provide for your image are as accurate as possible, as ARKit uses these to return the physicalSize and physicalWidth of your image which will allow your virtual content to placed more accurately (e.g if you specify a larger size than the actual size of your image in real life, your not going to be able to align your virtual content accurately).

正如@Trinca还说,您需要确保为图像提供的测量结果尽可能准确,因为ARKit使用这些测量值来返回图像的physicalSize和physicalWidth,这样可以更准确地放置虚拟内容(例如,如果您指定比实际生活中图像的实际尺寸更大的尺寸,您将无法准确对齐虚拟内容)。

AR参考图像平面在iOS Swift中位置不正确?

When creating a business card or any imageTarget we must make sure that our dimensions are accurately set in the ARReferenceImage Settings box:

在创建名片或任何imageTarget时,我们必须确保在ARReferenceImage设置框中准确设置我们的尺寸:

AR参考图像平面在iOS Swift中位置不正确?

We can then check to see if our imageTarget is detected like so:

然后我们可以检查我们的imageTarget是否被检测到:

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {

        //1. Check We Have Detected An ARImageAnchor & Check It's The One We Want
        guard let validImageAnchor = anchor as? ARImageAnchor,
              let targetName = validImageAnchor.referenceImage.name, targetName == "TargetCard" else { return}


        //2. Check To See The Detected Size Of Our Business Card (Should By 5cm*3cm)
        let businessCardWidth = validImageAnchor.referenceImage.physicalSize.width
        let businessCardHeight =  validImageAnchor.referenceImage.physicalSize.height

        print(
             """
              We Have Detected Business Card With Name \(targetName)
              \(targetName)'s Width Is \(businessCardWidth)
              \(targetName)'s Height Is \(businessCardHeight)
             """)

    }

Having checked that our detected size is accurate we can then place whatever content we like in relation to this.

在检查了我们检测到的大小是否准确之后,我们可以放置我们喜欢的与此相关的任何内容。

Rather than doing everything programatically, an easier way to achieve the results you are looking for is to create an SCNScene.

而不是以编程方式执行所有操作,实现所需结果的更简单方法是创建SCNScene。

Update:

更新:

As you have asked for an example project I have created a fully working example for everyone which can be download here: ARKit Business Card

正如您要求的示例项目,我为每个人创建了一个完整的工作示例,可以在这里下载:ARKit名片

Without going through every Class in detail I will provide you with the basic details.

如果没有详细介绍每个课程,我将为您提供基本的详细信息。

We will use an SCNScene as a reusable template, which contains a range of SCNNode which are used as buttons and which can perform different actions when they are pressed.

我们将使用SCNScene作为可重用模板,该模板包含一系列SCNNode,这些SCNNode用作按钮,可以在按下时执行不同的操作。

The basic template looks like so:

基本模板如下所示:

AR参考图像平面在iOS Swift中位置不正确?

The BusinessCard Node is initialised with A BusinessCardData Struct which looks like so:

BusinessCard节点使用A BusinessCardData Struct初始化,如下所示:

typealias SocialLinkData = (link: String, type: SocialLink)

/// The Information For The Business Card Node & Contact Details
struct BusinessCardData{

    var firstName: String
    var surname: String
    var position: String
    var company: String
    var address: BusinessAddress
    var website: SocialLinkData
    var phoneNumber: String
    var email: String
    var *Account: SocialLinkData
    var githubAccount: SocialLinkData

}

/// The Associates Business Address
struct BusinessAddress{

    var street: String
    var city: String
    var state: String
    var postalCode: String
    var coordinates: (latittude: Double, longtitude: Double)
}

/// The Type Of Social Link
///
/// - Website: Business Website
/// - *: * Account
/// - GitHub: Github Account
enum SocialLink: String{

    case Website
    case *
    case GitHub
}

Whereby all the data provided is mapped to each SCNNode in the template, and helps to perform the necessary functions.

因此,所提供的所有数据都映射到模板中的每个SCNNode,并有助于执行必要的功能。

By using a struct we can create multiple interactive business cards simply e.g:

通过使用结构,我们可以创建多个交互式名片,例如:

//--------------------------
//MARK: -  ARSessionDelegate
//--------------------------

extension  ViewController: ARSCNViewDelegate{

    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {

        //1. Check We Have A Valid Image Anchor
        guard let imageAnchor = anchor as? ARImageAnchor else { return }

        //2. Get The Detected Reference Image
        let referenceImage = imageAnchor.referenceImage

        //3. Load Our Business Card
        if let matchedBusinessCardName = referenceImage.name, matchedBusinessCardName == "BlackMirrorz"{

            //4. Create Our Business Card
            let businessCardData = BusinessCardData(firstName: "Josh",
                                                    surname: "Robbins",
                                                    position: "Software Engineer",
                                                    company: "BlackMirrorz",
                                                    address: BusinessAddress(street: "1 Infinite Loop",
                                                                             city: "Cupertino",
                                                                             state: "CA",
                                                                             postalCode: "95015",
                                                                             coordinates: (latittude: 37.3349, longtitude: -122.0090201)),
                                                    website: SocialLinkData(link: "https://www.blackmirrorz.tech", type: .Website),
                                                    phoneNumber: "+821076337633",
                                                    email: "josh.robbins@blackmirroz.tech",
                                                    *Account: SocialLinkData(link: "https://*.com/users/8816868/josh-robbins", type: .*),
                                                    githubAccount: SocialLinkData(link: "https://github.com/BlackMirrorz", type: .GitHub))

            //5. Assign It To The Business Card Node
            let businessCard = BusinessCard(data: businessCardData, cardType: .noProfileImage)
            businessCardPlaced = true
            node.addChildNode(businessCard)

        }
    }
}

Since the design is already laid out, we dont need to do any complex calculations. Everything is done for us!

由于设计已经布局,我们不需要进行任何复杂的计算。一切都为我们完成!

Interaction by the user is done using the following icons: AR参考图像平面在iOS Swift中位置不正确?

用户的交互使用以下图标完成:

  • The * Button presents a slide out WKWebView to display the users * Account.
  • *按钮显示滑出WKWebView以显示用户*帐户。
  • The GitHub Button presents a slide out WKWebView to display the users GitHub Account.
  • GitHub按钮显示滑出WKWebView以显示用户GitHub帐户。
  • The Internet Button presents a slide out WKWebView to display the users website.
  • Internet按钮显示滑出WKWebView以显示用户网站。
  • The Phone Button allows the user to call the Business Telephone Number.
  • 电话按钮允许用户拨打商务电话号码。
  • The SMS Button presents an MFMessageComposeViewController allowing the user to send a text message to the business.
  • SMS按钮提供MFMessageComposeViewController,允许用户向业务发送文本消息。
  • The Email Button presents an MFMailComposeViewController allowing the user to email the business.
  • 电子邮件按钮提供MFMailComposeViewController,允许用户通过电子邮件发送业务。
  • The Contact Button creates a CNMutableContact and saves the business as a new contact on the users device.
  • 联系人按钮创建CNMutableContact并将业务保存为用户设备上的新联系人。
  • The Location Button presents a slide out MKMapView to display the users Businesses Location.
  • “位置”按钮显示幻灯片MKMapView以显示用户“企业位置”。

Since rendering a WKWebView as an SCNMaterial, I had to look at other ways to allow the content to be fully interactive.

由于将WKWebView呈现为SCNMaterial,我不得不考虑其他方式来允许内容完全交互。

As such I made use of the fabulous repository SideMenu by Jonkykong which is available here: SideMenu

因此我使用了Jonkykong的神话般的存储库SideMenu,它可以在这里找到:SideMenu

This allows the user to still experience ARKit whilst allowing an almost split screen like effect:

这允许用户仍然体验ARKit,同时允许几乎分割屏幕效果:

AR参考图像平面在iOS Swift中位置不正确?

As always, hope it helps you and everyone else who is interested in learning ARKit...

一如既往,希望它能帮助您和其他有兴趣学习ARKit的人...

#2


2  

I had a similar problem and it was because a mistake setting the size of Reference Images.

我有类似的问题,这是因为设置参考图像的大小时出错。

If you're manually importing them to your "AR Resources Group", then you need to be sure to set "meters" or "centimetres" when typing the width and height on the right panel.

如果您手动将它们导入“AR资源组”,则在右侧面板上键入宽度和高度时,您需要确保设置“米”或“厘米”。

If you're loading those images from a server and than making them Reference Images, remember the default metric ARKit uses is "meters". In this case, if you set the width as 20.0, ARKit will consider 20 meters instead of 20 centimetres, bringing you a very inaccurate behaviour when tracking the image plane.

如果您从服务器加载这些图像而不是将它们作为参考图像,请记住ARKit使用的默认度量标准是“米”。在这种情况下,如果您将宽度设置为20.0,ARKit将考虑20米而不是20厘米,在跟踪图像平面时会给您带来非常不准确的行为。

Hope it helps.

希望能帮助到你。

#1


6  

The first thing you need to consider is whether you want to use ARWorldTrackingConfiguration or ARImageTrackingConfiguration (IOS12).

您需要考虑的第一件事是您是否要使用ARWorldTrackingConfiguration或ARImageTrackingConfiguration(IOS12)。

If you use ARImageTrackingConfiguration, you cant make use of PlaneDetection, as this is an Image Only tracking configuration:

如果您使用ARImageTrackingConfiguration,则无法使用PlaneDetection,因为这是一个Image Only跟踪配置:

which lets you anchor virtual content to known images only when those images are in view of the camera. World tracking with image detection lets you use known images to add virtual content to the 3D world, and continues to track the position of that content in world space even after the image is no longer in view.

只有当这些图像在相机视野中时,才能将虚拟内容锚定到已知图像。通过图像检测进行世界跟踪,您可以使用已知图像将虚拟内容添加到3D世界,并在图像不再可见时继续跟踪该内容在世界空间中的位置。

This would be your best bet, if you want your content to stay anchored to the image at all times (when in view of the camera) since:

如果您希望您的内容始终保持固定在图像上(在相机视野中),这将是您最好的选择,因为:

it tracks their movement with six degrees of freedom (6DOF): specifically, the three rotation axes (roll, pitch, and yaw), and three translation axes (movement in x, y, and z).

它以六个*度(6DOF)跟踪它们的运动:具体地说,三个旋转轴(滚动,俯仰和偏转)和三个平移轴(在x,y和z中的运动)。

On the other hand if you want to detect ARPlaneAnchors, as well as ARImageAnchors, but aren't bothered that any content associated with your ARImageAnchor won't track constantly then you should use ARWorldTrackingConfiguration.

另一方面,如果你想检测ARPlaneAnchors以及ARImageAnchors,但是不要担心任何与你的ARImageAnchor相关的内容不会不断跟踪,那么你应该使用ARWorldTrackingConfiguration。

As @Trinca also said you need to ensure that the measurements you provide for your image are as accurate as possible, as ARKit uses these to return the physicalSize and physicalWidth of your image which will allow your virtual content to placed more accurately (e.g if you specify a larger size than the actual size of your image in real life, your not going to be able to align your virtual content accurately).

正如@Trinca还说,您需要确保为图像提供的测量结果尽可能准确,因为ARKit使用这些测量值来返回图像的physicalSize和physicalWidth,这样可以更准确地放置虚拟内容(例如,如果您指定比实际生活中图像的实际尺寸更大的尺寸,您将无法准确对齐虚拟内容)。

AR参考图像平面在iOS Swift中位置不正确?

When creating a business card or any imageTarget we must make sure that our dimensions are accurately set in the ARReferenceImage Settings box:

在创建名片或任何imageTarget时,我们必须确保在ARReferenceImage设置框中准确设置我们的尺寸:

AR参考图像平面在iOS Swift中位置不正确?

We can then check to see if our imageTarget is detected like so:

然后我们可以检查我们的imageTarget是否被检测到:

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {

        //1. Check We Have Detected An ARImageAnchor & Check It's The One We Want
        guard let validImageAnchor = anchor as? ARImageAnchor,
              let targetName = validImageAnchor.referenceImage.name, targetName == "TargetCard" else { return}


        //2. Check To See The Detected Size Of Our Business Card (Should By 5cm*3cm)
        let businessCardWidth = validImageAnchor.referenceImage.physicalSize.width
        let businessCardHeight =  validImageAnchor.referenceImage.physicalSize.height

        print(
             """
              We Have Detected Business Card With Name \(targetName)
              \(targetName)'s Width Is \(businessCardWidth)
              \(targetName)'s Height Is \(businessCardHeight)
             """)

    }

Having checked that our detected size is accurate we can then place whatever content we like in relation to this.

在检查了我们检测到的大小是否准确之后,我们可以放置我们喜欢的与此相关的任何内容。

Rather than doing everything programatically, an easier way to achieve the results you are looking for is to create an SCNScene.

而不是以编程方式执行所有操作,实现所需结果的更简单方法是创建SCNScene。

Update:

更新:

As you have asked for an example project I have created a fully working example for everyone which can be download here: ARKit Business Card

正如您要求的示例项目,我为每个人创建了一个完整的工作示例,可以在这里下载:ARKit名片

Without going through every Class in detail I will provide you with the basic details.

如果没有详细介绍每个课程,我将为您提供基本的详细信息。

We will use an SCNScene as a reusable template, which contains a range of SCNNode which are used as buttons and which can perform different actions when they are pressed.

我们将使用SCNScene作为可重用模板,该模板包含一系列SCNNode,这些SCNNode用作按钮,可以在按下时执行不同的操作。

The basic template looks like so:

基本模板如下所示:

AR参考图像平面在iOS Swift中位置不正确?

The BusinessCard Node is initialised with A BusinessCardData Struct which looks like so:

BusinessCard节点使用A BusinessCardData Struct初始化,如下所示:

typealias SocialLinkData = (link: String, type: SocialLink)

/// The Information For The Business Card Node & Contact Details
struct BusinessCardData{

    var firstName: String
    var surname: String
    var position: String
    var company: String
    var address: BusinessAddress
    var website: SocialLinkData
    var phoneNumber: String
    var email: String
    var *Account: SocialLinkData
    var githubAccount: SocialLinkData

}

/// The Associates Business Address
struct BusinessAddress{

    var street: String
    var city: String
    var state: String
    var postalCode: String
    var coordinates: (latittude: Double, longtitude: Double)
}

/// The Type Of Social Link
///
/// - Website: Business Website
/// - *: * Account
/// - GitHub: Github Account
enum SocialLink: String{

    case Website
    case *
    case GitHub
}

Whereby all the data provided is mapped to each SCNNode in the template, and helps to perform the necessary functions.

因此,所提供的所有数据都映射到模板中的每个SCNNode,并有助于执行必要的功能。

By using a struct we can create multiple interactive business cards simply e.g:

通过使用结构,我们可以创建多个交互式名片,例如:

//--------------------------
//MARK: -  ARSessionDelegate
//--------------------------

extension  ViewController: ARSCNViewDelegate{

    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {

        //1. Check We Have A Valid Image Anchor
        guard let imageAnchor = anchor as? ARImageAnchor else { return }

        //2. Get The Detected Reference Image
        let referenceImage = imageAnchor.referenceImage

        //3. Load Our Business Card
        if let matchedBusinessCardName = referenceImage.name, matchedBusinessCardName == "BlackMirrorz"{

            //4. Create Our Business Card
            let businessCardData = BusinessCardData(firstName: "Josh",
                                                    surname: "Robbins",
                                                    position: "Software Engineer",
                                                    company: "BlackMirrorz",
                                                    address: BusinessAddress(street: "1 Infinite Loop",
                                                                             city: "Cupertino",
                                                                             state: "CA",
                                                                             postalCode: "95015",
                                                                             coordinates: (latittude: 37.3349, longtitude: -122.0090201)),
                                                    website: SocialLinkData(link: "https://www.blackmirrorz.tech", type: .Website),
                                                    phoneNumber: "+821076337633",
                                                    email: "josh.robbins@blackmirroz.tech",
                                                    *Account: SocialLinkData(link: "https://*.com/users/8816868/josh-robbins", type: .*),
                                                    githubAccount: SocialLinkData(link: "https://github.com/BlackMirrorz", type: .GitHub))

            //5. Assign It To The Business Card Node
            let businessCard = BusinessCard(data: businessCardData, cardType: .noProfileImage)
            businessCardPlaced = true
            node.addChildNode(businessCard)

        }
    }
}

Since the design is already laid out, we dont need to do any complex calculations. Everything is done for us!

由于设计已经布局,我们不需要进行任何复杂的计算。一切都为我们完成!

Interaction by the user is done using the following icons: AR参考图像平面在iOS Swift中位置不正确?

用户的交互使用以下图标完成:

  • The * Button presents a slide out WKWebView to display the users * Account.
  • *按钮显示滑出WKWebView以显示用户*帐户。
  • The GitHub Button presents a slide out WKWebView to display the users GitHub Account.
  • GitHub按钮显示滑出WKWebView以显示用户GitHub帐户。
  • The Internet Button presents a slide out WKWebView to display the users website.
  • Internet按钮显示滑出WKWebView以显示用户网站。
  • The Phone Button allows the user to call the Business Telephone Number.
  • 电话按钮允许用户拨打商务电话号码。
  • The SMS Button presents an MFMessageComposeViewController allowing the user to send a text message to the business.
  • SMS按钮提供MFMessageComposeViewController,允许用户向业务发送文本消息。
  • The Email Button presents an MFMailComposeViewController allowing the user to email the business.
  • 电子邮件按钮提供MFMailComposeViewController,允许用户通过电子邮件发送业务。
  • The Contact Button creates a CNMutableContact and saves the business as a new contact on the users device.
  • 联系人按钮创建CNMutableContact并将业务保存为用户设备上的新联系人。
  • The Location Button presents a slide out MKMapView to display the users Businesses Location.
  • “位置”按钮显示幻灯片MKMapView以显示用户“企业位置”。

Since rendering a WKWebView as an SCNMaterial, I had to look at other ways to allow the content to be fully interactive.

由于将WKWebView呈现为SCNMaterial,我不得不考虑其他方式来允许内容完全交互。

As such I made use of the fabulous repository SideMenu by Jonkykong which is available here: SideMenu

因此我使用了Jonkykong的神话般的存储库SideMenu,它可以在这里找到:SideMenu

This allows the user to still experience ARKit whilst allowing an almost split screen like effect:

这允许用户仍然体验ARKit,同时允许几乎分割屏幕效果:

AR参考图像平面在iOS Swift中位置不正确?

As always, hope it helps you and everyone else who is interested in learning ARKit...

一如既往,希望它能帮助您和其他有兴趣学习ARKit的人...

#2


2  

I had a similar problem and it was because a mistake setting the size of Reference Images.

我有类似的问题,这是因为设置参考图像的大小时出错。

If you're manually importing them to your "AR Resources Group", then you need to be sure to set "meters" or "centimetres" when typing the width and height on the right panel.

如果您手动将它们导入“AR资源组”,则在右侧面板上键入宽度和高度时,您需要确保设置“米”或“厘米”。

If you're loading those images from a server and than making them Reference Images, remember the default metric ARKit uses is "meters". In this case, if you set the width as 20.0, ARKit will consider 20 meters instead of 20 centimetres, bringing you a very inaccurate behaviour when tracking the image plane.

如果您从服务器加载这些图像而不是将它们作为参考图像,请记住ARKit使用的默认度量标准是“米”。在这种情况下,如果您将宽度设置为20.0,ARKit将考虑20米而不是20厘米,在跟踪图像平面时会给您带来非常不准确的行为。

Hope it helps.

希望能帮助到你。