AR 参考图像平面在 iOS Swift 中的位置不正确?
AR refernce image plane was not position properly in iOS Swift?
我正在使用 ar 参考图像处理名片个人资料信息。当参考检测到时,它将显示公司首席执行官详细信息、地址、照片和团队成员信息等。最初检测到图像时,它的平面将使用 runAction amintion 向右移动。
我的问题被检测到ar refrence,飞机位置稳定并且它在这里和那里移动。如何用ar参考图像拟合平面位置。
这是我的结果的屏幕截图:[![在此处输入图片描述][1]][1]
这是我使用的代码:
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
}
}
像这样的 ar 参考平面的异常结果将适合卡片 https://www.facebook.com/oscarfalmer/videos/10156651667309345/
我遇到了类似的问题,这是因为设置参考图像的大小错误。
如果您手动将它们导入 "AR Resources Group",那么在右侧面板上输入宽度和高度时,您需要确保设置 "meters" 或 "centimetres"。
如果您从服务器加载这些图像而不是将它们制作成参考图像,请记住 ARKit 使用的默认指标是 "meters"。在这种情况下,如果您将宽度设置为 20.0,ARKit 将考虑 20 米而不是 20 厘米,从而在跟踪图像平面时给您带来非常不准确的行为。
希望对您有所帮助。
你首先要考虑的是你要用ARWorldTrackingConfiguration
还是ARImageTrackingConfiguration
(IOS12
)。
如果您使用 ARImageTrackingConfiguration
,则无法使用 PlaneDetection,因为这是一个仅图像跟踪配置:
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.
如果您希望您的内容始终固定在图像上(在摄像头视野范围内),这将是您的最佳选择,因为:
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).
另一方面,如果您想要检测 ARPlaneAnchors
以及 ARImageAnchors
,但不担心与您的 ARImageAnchor
相关的任何内容不会持续跟踪那么你应该使用 ARWorldTrackingConfiguration
.
正如@Trinca 所说,您需要确保为图像提供的测量值尽可能准确,因为 ARKit
将这些用于 return physicalSize
和 physicalWidth
你的图像,这将使你的虚拟内容放置得更准确(例如,如果你指定的尺寸比现实生活中图像的实际尺寸大,你将无法准确对齐你的虚拟内容)。
创建名片或任何 imageTarget 时,我们必须确保我们的尺寸在 ARReferenceImage Settings
框中准确设置:
然后我们可以检查我们的 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)
""")
}
检查我们检测到的大小是否准确后,我们就可以放置与此相关的任何我们喜欢的内容。
与其以编程方式执行所有操作,获得所需结果的更简单方法是创建 SCNScene
.
更新:
正如您要求的示例项目,我已经为每个人创建了一个可以在此处下载的完整示例:ARKit Business Card
我不会详细介绍每个 Class
,我将为您提供基本的详细信息。
我们将使用 SCNScene
作为可重复使用的模板,其中包含一系列 SCNNode
,用作按钮,按下时可以执行不同的操作。
基本模板如下所示:
使用 BusinessCardData 结构初始化 BusinessCard 节点,如下所示:
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 WhosebugAccount: 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
/// - Whosebug: Whosebug Account
/// - GitHub: Github Account
enum SocialLink: String{
case Website
case Whosebug
case GitHub
}
由此提供的所有数据都映射到模板中的每个 SCNNode
,并有助于执行必要的功能。
通过使用 struct
我们可以创建多个交互式名片,例如:
//--------------------------
//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",
WhosebugAccount: SocialLinkData(link: "https://whosebug.com/users/8816868/josh-robbins", type: .Whosebug),
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)
}
}
}
由于设计已经布局,我们不需要做任何复杂的计算。一切都为我们做好了!
用户使用以下图标进行交互:
Whosebug Button
显示一个滑出 WKWebView
以显示用户 Whosebug
帐户。
GitHub Button
显示一个滑出 WKWebView
以显示用户 GitHub
帐户。
Internet Button
显示一个幻灯片 WKWebView
以显示用户网站。
Phone Button
允许用户拨打商务电话号码。
SMS Button
显示一个 MFMessageComposeViewController
允许用户向企业发送短信。
Email Button
提供了一个 MFMailComposeViewController
允许用户给公司发电子邮件。
Contact Button
创建一个 CNMutableContact
并将公司保存为用户设备上的新联系人。
Location Button
显示一个幻灯片 MKMapView
以显示用户的商家位置。
自从将 WKWebView
渲染为 SCNMaterial
后,我不得不寻找其他方式来让内容完全互动。
因此,我使用了 Jonkykong
的精彩存储库 SideMenu
,可在此处获得:
SideMenu
这允许用户仍然体验 ARKit
,同时允许类似分屏的效果:
一如既往,希望对您和其他有兴趣学习 ARKit 的人有所帮助...
我正在使用 ar 参考图像处理名片个人资料信息。当参考检测到时,它将显示公司首席执行官详细信息、地址、照片和团队成员信息等。最初检测到图像时,它的平面将使用 runAction amintion 向右移动。
我的问题被检测到ar refrence,飞机位置稳定并且它在这里和那里移动。如何用ar参考图像拟合平面位置。
这是我的结果的屏幕截图:[![在此处输入图片描述][1]][1]
这是我使用的代码:
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
}
}
像这样的 ar 参考平面的异常结果将适合卡片 https://www.facebook.com/oscarfalmer/videos/10156651667309345/
我遇到了类似的问题,这是因为设置参考图像的大小错误。
如果您手动将它们导入 "AR Resources Group",那么在右侧面板上输入宽度和高度时,您需要确保设置 "meters" 或 "centimetres"。
如果您从服务器加载这些图像而不是将它们制作成参考图像,请记住 ARKit 使用的默认指标是 "meters"。在这种情况下,如果您将宽度设置为 20.0,ARKit 将考虑 20 米而不是 20 厘米,从而在跟踪图像平面时给您带来非常不准确的行为。
希望对您有所帮助。
你首先要考虑的是你要用ARWorldTrackingConfiguration
还是ARImageTrackingConfiguration
(IOS12
)。
如果您使用 ARImageTrackingConfiguration
,则无法使用 PlaneDetection,因为这是一个仅图像跟踪配置:
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.
如果您希望您的内容始终固定在图像上(在摄像头视野范围内),这将是您的最佳选择,因为:
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).
另一方面,如果您想要检测 ARPlaneAnchors
以及 ARImageAnchors
,但不担心与您的 ARImageAnchor
相关的任何内容不会持续跟踪那么你应该使用 ARWorldTrackingConfiguration
.
正如@Trinca 所说,您需要确保为图像提供的测量值尽可能准确,因为 ARKit
将这些用于 return physicalSize
和 physicalWidth
你的图像,这将使你的虚拟内容放置得更准确(例如,如果你指定的尺寸比现实生活中图像的实际尺寸大,你将无法准确对齐你的虚拟内容)。
创建名片或任何 imageTarget 时,我们必须确保我们的尺寸在 ARReferenceImage Settings
框中准确设置:
然后我们可以检查我们的 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)
""")
}
检查我们检测到的大小是否准确后,我们就可以放置与此相关的任何我们喜欢的内容。
与其以编程方式执行所有操作,获得所需结果的更简单方法是创建 SCNScene
.
更新:
正如您要求的示例项目,我已经为每个人创建了一个可以在此处下载的完整示例:ARKit Business Card
我不会详细介绍每个 Class
,我将为您提供基本的详细信息。
我们将使用 SCNScene
作为可重复使用的模板,其中包含一系列 SCNNode
,用作按钮,按下时可以执行不同的操作。
基本模板如下所示:
使用 BusinessCardData 结构初始化 BusinessCard 节点,如下所示:
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 WhosebugAccount: 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
/// - Whosebug: Whosebug Account
/// - GitHub: Github Account
enum SocialLink: String{
case Website
case Whosebug
case GitHub
}
由此提供的所有数据都映射到模板中的每个 SCNNode
,并有助于执行必要的功能。
通过使用 struct
我们可以创建多个交互式名片,例如:
//--------------------------
//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",
WhosebugAccount: SocialLinkData(link: "https://whosebug.com/users/8816868/josh-robbins", type: .Whosebug),
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)
}
}
}
由于设计已经布局,我们不需要做任何复杂的计算。一切都为我们做好了!
用户使用以下图标进行交互:
Whosebug Button
显示一个滑出WKWebView
以显示用户Whosebug
帐户。GitHub Button
显示一个滑出WKWebView
以显示用户GitHub
帐户。Internet Button
显示一个幻灯片WKWebView
以显示用户网站。Phone Button
允许用户拨打商务电话号码。SMS Button
显示一个MFMessageComposeViewController
允许用户向企业发送短信。Email Button
提供了一个MFMailComposeViewController
允许用户给公司发电子邮件。Contact Button
创建一个CNMutableContact
并将公司保存为用户设备上的新联系人。Location Button
显示一个幻灯片MKMapView
以显示用户的商家位置。
自从将 WKWebView
渲染为 SCNMaterial
后,我不得不寻找其他方式来让内容完全互动。
因此,我使用了 Jonkykong
的精彩存储库 SideMenu
,可在此处获得:
SideMenu
这允许用户仍然体验 ARKit
,同时允许类似分屏的效果:
一如既往,希望对您和其他有兴趣学习 ARKit 的人有所帮助...