Swift 添加按钮到 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...
这篇关于Swift 添加按钮到 SCNNode的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!