在XZ平面上拖动对象

时间:2018-01-11 15:15:50

标签: ios scenekit arkit

我正在开发一个增强现实应用程序,我希望能够在空间中拖动一个对象。我在SO中找到的解决方案的问题,即建议使用projectPoint / unprojectPoint的问题,是它们沿着 XY 平面产生移动。

我试图将屏幕上的手指移动作为节点的 x z 坐标的偏移量。问题是需要考虑很多东西(摄像机的位置,节点的位置,节点的旋转等)。

有更简单的方法吗?

3 个答案:

答案 0 :(得分:1)

首先你需要创建低于原点的几米(我有10个)的地板或非常大的平面。这可以确保您的hittest始终返回值。然后使用平移手势:

//store previous coordinates from hittest to compare with current ones
var PCoordx: Float = 0.0
var PCoordz: Float = 0.0

@objc func move(_ gestureRecognizer: UIPanGestureRecognizer){
    if gestureRecognizer.state == .began{
        let hitNode = sceneView.hitTest(gestureRecognizer.location(in: sceneView), options: nil)
        PCoordx = (hitNode.first?.worldCoordinates.x)!
        PCoordz = (hitNode.first?.worldCoordinates.z)!
    }

    // when you start to pan in screen with your finger
    // hittest gives new coordinates of touched location in sceneView
    // coord-pcoord gives distance to move or distance paned in sceneview 
    if gestureRecognizer.state == .changed {
        let hitNode = sceneView.hitTest(gestureRecognizer.location(in: sceneView), options: nil)
        if let coordx = hitNode.first?.worldCoordinates.x{
            if let coordz = hitNode.first?.worldCoordinates.z{

            let action = SCNAction.moveBy(x: CGFloat(coordx-PCoordx), y: 0, z: CGFloat(coordz-PCoordz), duration: 0.1)
            node.runAction(action)

            PCoordx = coordx
            PCoordz = coordz
            }
        }

        gestureRecognizer.setTranslation(CGPoint.zero, in: sceneView)
    }
    if gestureRecognizer.state == .ended{
        PCoordx = 0
        PCoordz = 0
    }
}

在我的情况下,只有一个节点,所以我没有检查是否有必要的节点。如果您有许多节点,可以随时检查它。

答案 1 :(得分:0)

我已经更新了 @Alok 答案,因为就我而言,它只是从上述解决方案中拖入x平面。所以我添加了y坐标,为我工作。

var PCoordx: Float = 0.0
var PCoordy: Float = 0.0
var PCoordz: Float = 0.0

@objc func handleDragGesture(_ sender: UIPanGestureRecognizer) {

    switch sender.state {
    case .began:
        let hitNode = self.sceneView.hitTest(sender.location(in: self.sceneView),
                                             options: nil)
        self.PCoordx = (hitNode.first?.worldCoordinates.x)!
        self.PCoordy = (hitNode.first?.worldCoordinates.y)!
        self.PCoordz = (hitNode.first?.worldCoordinates.z)!
    case .changed:
        // when you start to pan in screen with your finger
        // hittest gives new coordinates of touched location in sceneView
        // coord-pcoord gives distance to move or distance paned in sceneview
        let hitNode = sceneView.hitTest(sender.location(in: sceneView), options: nil)
        if let coordx = hitNode.first?.worldCoordinates.x,
            let coordy = hitNode.first?.worldCoordinates.y,
            let coordz = hitNode.first?.worldCoordinates.z {
            let action = SCNAction.moveBy(x: CGFloat(coordx - PCoordx),
                                          y: CGFloat(coordy - PCoordy),
                                          z: CGFloat(coordz - PCoordz),
                                          duration: 0.0)
            self.photoNode.runAction(action)

            self.PCoordx = coordx
            self.PCoordy = coordy
            self.PCoordz = coordz
        }

        sender.setTranslation(CGPoint.zero, in: self.sceneView)
    case .ended:
        self.PCoordx = 0.0
        self.PCoordy = 0.0
        self.PCoordz = 0.0
    default:
        break
    }
}

答案 2 :(得分:-1)

如果我理解正确,我会使用添加到ARSCNView的UIPanGestureRecognizer执行此操作。

在我的情况下,我想检查pan是否在给定的虚拟对象上启动并跟踪它是什么,因为我可以有多个,但如果你只有一个对象,则可能不需要 targetNode 变量。 我使用700常量来划分我通过反复试验得到它使翻译更顺畅,你可能需要根据你的情况改变它。

向上移动手指,将物体远离相机移动并向下移动物体使其移近。手指的水平移动会使物体向左/向右移动。

@objc func onTranslate(_ sender: UIPanGestureRecognizer) {
    let position = sender.location(in: scnView)
    let state = sender.state

    if (state == .failed || state == .cancelled) {
        return
    }

    if (state == .began) {
        // Check pan began on a virtual object
        if let objectNode = virtualObject(at: position).node {
            targetNode = objectNode
            latestTranslatePos = position
        }
    }
    else if let _ = targetNode {

        // Translate virtual object
        let deltaX = Float(position.x - latestTranslatePos!.x)/700
        let deltaY = Float(position.y - latestTranslatePos!.y)/700

        targetNode!.localTranslate(by: SCNVector3Make(deltaX, 0.0, deltaY))
        latestTranslatePos = position

        if (state == .ended) {
            targetNode = nil
        }
    }