iOS 11 ARKit:在3D视图中拖动对象

我在3d视图中有一个节点对象,我需要拖动该对象,到目前为止我已经尝试过: 在ARKit中放置,拖动和删除SCNNode

并迅速转换

@objc func handleDragGesture(_ gestureRecognizer: UIGestureRecognizer) { let tapPoint = gestureRecognizer.location(in: self.sceneView) switch gestureRecognizer.state { case .began: print("Object began to move") let hitResults = self.sceneView.hitTest(tapPoint, options: nil) if hitResults.isEmpty { return } let hitResult = hitResults.first if let node = hitResult?.node.parent?.parent?.parent { self.photoNode = node } case .changed: print("Moving object position changed") if let _ = self.photoNode { let hitResults = self.sceneView.hitTest(tapPoint, types: .featurePoint) let hitResult = hitResults.last if let transform = hitResult?.worldTransform { let matrix = SCNMatrix4FromMat4(transform) let vector = SCNVector3Make(matrix.m41, matrix.m42, matrix.m43) self.photoNode?.position = vector } } case .ended: print("Done moving object") default: break } } 

但它不能正常工作。 什么是正确的方法?

您可以使用panGestureRecongniser执行此操作…请参阅用于处理SCNNode的基本swift Playground代码。

 import UIKit import ARKit import SceneKit import PlaygroundSupport public var textNode : SCNNode? // Main ARKIT ViewController class ViewController : UIViewController, ARSCNViewDelegate, ARSessionDelegate { var textNode: SCNNode! var counter = 0 @IBOutlet var sceneView: ARSCNView! override func viewDidLoad() { super.viewDidLoad() // set the views delegate sceneView.delegate = self as! ARSCNViewDelegate // show statistics such as fps and timing information sceneView.showsStatistics = true // Create a new scene sceneView.scene.rootNode // Add ligthing sceneView.autoenablesDefaultLighting = true let text = SCNText(string: "Drag Me with Pan Gesture!", extrusionDepth: 1) // create material let material = SCNMaterial() material.diffuse.contents = UIColor.green text.materials = [material] //Create Node object textNode = SCNNode() textNode.name = "textNode" textNode.scale = SCNVector3(x:0.004,y:0.004,z:0.004) textNode.geometry = text textNode.position = SCNVector3(x: 0, y:0.02, z: -1) // add new node to root node self.sceneView.scene.rootNode.addChildNode(textNode) // Add pan gesture for dragging the textNode about sceneView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(panGesture(_:)))) } override func loadView() { sceneView = ARSCNView(frame:CGRect(x: 0.0, y: 0.0, width: 500.0, height: 600.0)) // Set the view's delegate sceneView.delegate = self let config = ARWorldTrackingConfiguration() config.planeDetection = .horizontal // Now we'll get messages when planes were detected... sceneView.session.delegate = self self.view = sceneView sceneView.session.run(config) } @objc func panGesture(_ gesture: UIPanGestureRecognizer) { gesture.minimumNumberOfTouches = 1 let results = self.sceneView.hitTest(gesture.location(in: gesture.view), types: ARHitTestResult.ResultType.featurePoint) guard let result: ARHitTestResult = results.first else { return } let position = SCNVector3Make(result.worldTransform.columns.3.x, result.worldTransform.columns.3.y, result.worldTransform.columns.3.z) textNode.position = position } } PlaygroundPage.current.liveView = ViewController() PlaygroundPage.current.needsIndefiniteExecution = true 

编辑:

上面的拖动function仅在视图中有1个对象时才有效,因此没有必要点击节点开始拖动。 它只会拖动您点击屏幕的位置。 如果视图中有多个对象,并且您希望独立拖动节点。 您可以将panGesturefunction更改为以下内容,检测首先点击的每个节点:

//独立拖动节点

 @objc func panGesture(_ gesture: UIPanGestureRecognizer) { gesture.minimumNumberOfTouches = 1 let results = self.sceneView.hitTest(gesture.location(in: gesture.view), types: ARHitTestResult.ResultType.featurePoint) guard let result: ARHitTestResult = results.first else { return } let hits = self.sceneView.hitTest(gesture.location(in: gesture.view), options: nil) if let tappedNode = hits.first?.node { let position = SCNVector3Make(result.worldTransform.columns.3.x, result.worldTransform.columns.3.y, result.worldTransform.columns.3.z) tappedNode.position = position } }