快速添加按钮到SCNNode [英] Swift Add Button to SCNNode
问题描述
我正在玩ARKit和图像检测. 现在,我有一个应用程序,该应用程序可以检测图像并在屏幕上将检测到的对象放置在平面上.
I'm playing around with the ARKit and image detection. Now I have an app that detects images an places planes on the screen where the detected objects are.
如何在飞机上添加可点击元素,例如按钮.我想对每个检测到的对象都单击事件.
How can I add a clickable element like a button on the planes. I want to have a click event on each detected object.
这是我的渲染器函数的外观:
This is what my renderer function looks:
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
guard let imageAnchor = anchor as? ARImageAnchor else { return }
let referenceImage = imageAnchor.referenceImage
updateQueue.async {
let plane = SCNPlane(width: referenceImage.physicalSize.width,
height: referenceImage.physicalSize.height)
let planeNode = SCNNode(geometry: plane)
planeNode.opacity = 0.25
planeNode.eulerAngles.x = -.pi / 2
planeNode.runAction(self.imageHighlightAction)
node.addChildNode(planeNode)
}
DispatchQueue.main.async {
let imageName = referenceImage.name ?? ""
self.statusViewController.cancelAllScheduledMessages()
// self.statusViewController.showMessage("Detected image "\(imageName)"")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let second = storyboard.instantiateViewController(withIdentifier: "InfoViewController")as! InfoViewController
second.myStringValue = imageName
// self.navigationController?.pushViewController(second, animated: true)
}
}
推荐答案
有几种方法可以解决此问题:
There are a few ways you can approach this:
1:标准方法:
在您的delegate
方法中,按以下方式为每个节点分配一个名称(显然,如果您有很多节点,您将根据需要将它们存储在数组或字典中):
In your delegate
method, assign each node a name as per below (clearly if you have lots of nodes you would want to store them in an Array or Dictionary depending upon your needs):
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
//1. Check We Have The Image Anchor
guard let imageAnchor = anchor as? ARImageAnchor else { return }
//2. Get The Reference Image
let referenceImage = imageAnchor.referenceImage
//1. Create The Plane Geometry With Our Width & Height Parameters
let planeGeometry = SCNPlane(width: referenceImage.physicalSize.width,
height: referenceImage.physicalSize.height)
//2. Create A New Material
let material = SCNMaterial()
material.diffuse.contents = UIColor.red
//3. Create The Plane Node
let planeNode = SCNNode(geometry: planeGeometry)
planeNode.geometry?.firstMaterial = material
planeNode.opacity = 0.25
planeNode.eulerAngles.x = -.pi / 2
//4. Add A Name To The Node
planeNode.name = "I Was Clicked"
//5. Add It To The Scene
node.addChildNode(planeNode)
}
然后使用touchesBegan
进行一次hitTest并相应地处理触摸:
Then using touchesBegan
, perform a hitTest and handle your touch accordingly:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
/*
1. Get The Current Touch Location
2. Check That We Have Touched A Valid Node
3. Check If The Node Has A Name
4. Handle The Touch
*/
guard let touchLocation = touches.first?.location(in: augmentedRealityView),
let hitNode = augmentedRealityView?.hitTest(touchLocation, options: nil).first?.node,
let nodeName = hitNode.name
else {
//No Node Has Been Tapped
return
}
//Handle Event Here e.g. PerformSegue
print(nodeName)
}
2:一种有趣的方法:
UIKit
元素实际上可以作为SCNGeometry's Material
添加.我个人没有见过很多人使用这种方法,但是对于想将UIKit
与ARKit
结合的人来说,它可能很有用.
UIKit
elements can actually be added as an SCNGeometry's Material
. I personally haven't seen many people use this approach, but it may prove useful to anyone who wants to incorporate UIKit
with ARKit
.
创建自定义UIButton,例如:
Create A Custom UIButton e.g:
/// Clickable View
class ClickableView: UIButton{
override init(frame: CGRect) {
super.init(frame: frame)
self.addTarget(self, action: #selector(objectTapped(_:)), for: .touchUpInside)
self.backgroundColor = .red
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
/// Detects Which Object Was Tapped
///
/// - Parameter sender: UIButton
@objc func objectTapped(_ sender: UIButton){
print("Object With Tag \(tag)")
}
}
然后在您的委托方法中执行以下操作:
And in your delegate method do the following:
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
//1. Check We Have The Image Anchor
guard let imageAnchor = anchor as? ARImageAnchor else { return }
//2. Get The Reference Image
let referenceImage = imageAnchor.referenceImage
//1. Create The Plane Geometry With Our Width & Height Parameters
let planeGeometry = SCNPlane(width: referenceImage.physicalSize.width,
height: referenceImage.physicalSize.height)
//2. Create A New Material
let material = SCNMaterial()
DispatchQueue.main.async {
//3. Create The New Clickable View
let clickableElement = ClickableView(frame: CGRect(x: 0, y: 0,
width: 300,
height: 300))
clickableElement.tag = 1
//4. Add The Clickable View As A Materil
material.diffuse.contents = clickableElement
}
//5. Create The Plane Node
let planeNode = SCNNode(geometry: planeGeometry)
planeNode.geometry?.firstMaterial = material
planeNode.opacity = 0.25
planeNode.eulerAngles.x = -.pi / 2
//6. Add It To The Scene
node.addChildNode(planeNode)
}
这应该让您入门...
This should get you started...
这篇关于快速添加按钮到SCNNode的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!