iOS 11 ARKit:在 3D 视图中拖动对象 [英] iOS 11 ARKit : Drag Object in 3D View

查看:28
本文介绍了iOS 11 ARKit:在 3D 视图中拖动对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a node object in 3d view and i need to drag that object, So far i have tried from here : Placing, Dragging and Removing SCNNodes in ARKit

并迅速转换

@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
        }
    }

但它无法正常工作.正确的做法是什么?

but it is not working properly. what is the correct way to do?

推荐答案

您可以使用 panGestureRecongniser 来做到这一点...请参阅处理 SCNNode 的基本 Swift Playground 代码.

You can do this using panGestureRecongniser... see basic swift Playground code for handling a SCNNode.

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 

上述拖动功能仅在视图中有 1 个对象时才起作用,因此实际上没有必要点击节点来开始拖动.它只会从您在屏幕上点击的位置拖动.如果视图中有多个对象,并且想要独立拖动节点.您可以将 panGesture 函数更改为以下内容,首先检测每个节点:

The above drag function only worked if you had 1 object in the view, so it was not really necessary to hit the node to start dragging. It will just drag from where ever you tapped on the screen. If you have multiple objects in the view, and you want to drag nodes independently. You could change the panGesture function to the following, detect each node tapped first:

//独立拖动节点

@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
    }

} 

这篇关于iOS 11 ARKit:在 3D 视图中拖动对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆