swift - 如何在命中测试 ARKit SceneKit 中找到飞机的中心
问题描述
在图像检测应用程序中,图像被识别,然后创建一个不透明的覆盖平面,因此当用户在屏幕上点击时,命中测试会找到覆盖平面,并且可以创建一个新对象。但我想将对象准确定位在底层图像的中心。我怎样才能让它始终位于图像/平面的中心,并具有相同的方向。这可以从命中测试结果中得到吗?感谢您的任何建议!
@objc func handleScreenTap(sender: UITapGestureRecognizer) {
let tappedSceneView = sender.view as! ARSCNView
let tapLocation = sender.location(in: tappedSceneView)
let planeIntersections = tappedSceneView.hitTest(tapLocation, types: [.estimatedHorizontalPlane, .estimatedVerticalPlane])
if !planeIntersections.isEmpty {
addSceneAtPositionOnPlane(hitTestResult: planeIntersections.first!)
}
func addSceneAtPositionOnPlane(hitTestResult: ARHitTestResult) {
let transform = hitTestResult.worldTransform
let positionColumn = transform.columns.3
let initialPosition = SCNVector3(positionColumn.x,
positionColumn.y,
positionColumn.z)
let node = self.createScene(for: initialPosition)
sceneView.scene.rootNode.addChildNode(node)
}
func createScene(for position: SCNVector3) -> SCNNode {
let box = SCNNode(geometry: SCNBox(width: 0.1, //x
height: 0.1, //y
length: 0.1, //z
chamferRadius: 0))
box.geometry?.firstMaterial?.diffuse.contents = UIColor.red
box.geometry?.firstMaterial?.isDoubleSided = true
box.opacity = 0.8
box.position = position
return box
}
解决方案
如果您已经添加了一个 SCNNode 来在检测到的图像之上渲染一个平面,那么您可以只使用返回 SceneKit 节点的 SceneKit hitTest 方法,而不是尝试对 ARKit 几何体进行命中测试。
一旦您将平面添加到场景中,您就可以将新几何图形添加为该节点的子节点。
这是一个示例,一旦检测到图像,就会在其顶部绘制一个平面,然后当用户单击该平面时,会添加一个框作为子项,然后该框将跟随跟踪的图像并具有正确的位置和方向。
import UIKit
import SceneKit
import ARKit
class ViewController: UIViewController, ARSCNViewDelegate {
@IBOutlet var sceneView: ARSCNView!
override func viewDidLoad() {
super.viewDidLoad()
sceneView.delegate = self
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(onTap))
sceneView.addGestureRecognizer(tapGesture)
}
@objc func onTap(_ recognizer: UITapGestureRecognizer) {
let point = recognizer.location(in: sceneView)
guard let hit = sceneView.hitTest(point, options: nil).first else {
return
}
let box = SCNBox(width: 0.02, height: 0.02, length: 0.02, chamferRadius: 0)
let node = SCNNode(geometry: box)
node.position = SCNVector3(0, 0, 0.01)
box.materials.first?.diffuse.contents = UIColor.red
hit.node.addChildNode(node)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let configuration = ARWorldTrackingConfiguration()
guard let images = ARReferenceImage.referenceImages(inGroupNamed: "ARTest", bundle: nil) else {
return
}
configuration.detectionImages = images
configuration.maximumNumberOfTrackedImages = 1
sceneView.session.run(configuration)
}
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
guard let imageAnchor = anchor as? ARImageAnchor else {
return
}
let size = imageAnchor.referenceImage.physicalSize
let plane = SCNPlane(width: size.width, height: size.height)
let planeNode = SCNNode(geometry: plane)
planeNode.eulerAngles.x = -Float.pi / 2
planeNode.opacity = 0.9
node.addChildNode(planeNode)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
sceneView.session.pause()
}
}
推荐阅读
- python - 如何在嵌套函数中评估外部范围的变量?
- java - 在我的 getter 方法中格式化双重问题
- c# - 我的 C# JavaScriptSerializer 输出为空?
- powershell - REVERSE - DISM /Online /Remove-ProvisionedAppxPackage /PackageName:Microsoft.WindowsCalculator_2018.702.514.0_neutral_~_8wekyb3d8bbwe
- php - 如何使用特定的 html 表设置 php
- angular - Angular 2 Select Label 占位符被覆盖
- c# - 当内容类型为application / x-www-form-urlencoded .net core时如何使用帖子数据
- c# - 无法从 Angular UI 发布到 ASP.NET WebApi
- php - 将 jQuery 值分配给 ajax susss 中的 PHP 变量
- ios - 通过 Cordova/Phonegap 应用程序创建一个可以由另一个应用程序 (ios) 打开的文件?