iOS - ARKit - 如何创建旋转物体手势函数?

5

我是ARKit新手,想要创建一个旋转物体的功能。这是我的有关拖动和旋转对象的代码:

// Rotate object
@objc func rotateRecognized(sender: UIPanGestureRecognizer) {
    let sceneView = sender.view as! ARSCNView
    let swipeLocation = sender.location(in: sceneView)
    let hitTest = sceneView.hitTest(swipeLocation)
    if !hitTest.isEmpty {
        sender.minimumNumberOfTouches = 2
        let results = hitTest.first!
        let node = results.node
        let xPan = sender.velocity(in: sceneView).x/10000
        node.runAction(SCNAction.rotateBy(x: 0, y: xPan, z: 0, duration: 0.1))
    }
}

// Drag object
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    //1. Get The Current Touch Point
    guard let currentTouchPoint = touches.first?.location(in: self.sceneView),
        //2. Get The Next Feature Point Etc
        let hitTest = sceneView.hitTest(currentTouchPoint, types: .existingPlane).first else { return }

    //3. Convert To World Coordinates
    let worldTransform = hitTest.worldTransform

    //4. Set The New Position
    let newPosition = SCNVector3(worldTransform.columns.3.x, worldTransform.columns.3.y, worldTransform.columns.3.z)

    //5. Apply To The Node
    self.sceneView.scene.rootNode.enumerateChildNodes{ (node, _) in
       node.simdPosition = float3(newPosition.x, newPosition.y, newPosition.z)
    }

}

当我拖动一个对象时,它能正常工作。但是当我用两个手指滑动旋转对象时,直到我移除touchesMoves方法,该对象无法旋转。 如何解决这个问题?谢谢。
1个回答

13

我认为最好使用GestureRecognizers来处理这个问题,而不是将touchesgestures结合起来使用。

因此,让我们看看如何解决这个问题。

您已经具备拖动SCNNode的功能,这很容易转换成一个UIPanGesture,您还想要一个围绕Y轴旋转SCNNode的函数,我们可以通过UIRotationGestureRecognizer轻松实现。

在我的示例中,我有一个名为currentNode的SCNNode,当然,您的会不同。

首先,我们将创建两个变量:

//Store The Rotation Of The CurrentNode
var currentAngleY: Float = 0.0

//Not Really Necessary But Can Use If You Like 
var isRotating = false

接下来,我们将在viewDidLoad中创建两个gestureRecognizers

 let panGesture = UIPanGestureRecognizer(target: self, action: #selector(moveNode(_:)))
 self.view.addGestureRecognizer(panGesture)

 let rotateGesture = UIRotationGestureRecognizer(target: self, action: #selector(rotateNode(_:)))
 self.view.addGestureRecognizer(rotateGesture)

完成此操作后,我们需要创建函数。

第一个函数将处理拖动当前节点,例如:

/// Rotates An Object On It's YAxis
///
/// - Parameter gesture: UIPanGestureRecognizer
@objc func moveNode(_ gesture: UIPanGestureRecognizer) {

    if !isRotating{

    //1. Get The Current Touch Point
    let currentTouchPoint = gesture.location(in: self.augmentedRealityView)

    //2. Get The Next Feature Point Etc
    guard let hitTest = self.augmentedRealityView.hitTest(currentTouchPoint, types: .existingPlane).first else { return }

    //3. Convert To World Coordinates
    let worldTransform = hitTest.worldTransform

    //4. Set The New Position
    let newPosition = SCNVector3(worldTransform.columns.3.x, worldTransform.columns.3.y, worldTransform.columns.3.z)

    //5. Apply To The Node
    currentNode.simdPosition = float3(newPosition.x, newPosition.y, newPosition.z)

    }
}

第二个是绕Y轴旋转:

/// Rotates An SCNNode Around It's YAxis
///
/// - Parameter gesture: UIRotationGestureRecognizer
@objc func rotateNode(_ gesture: UIRotationGestureRecognizer){

    //1. Get The Current Rotation From The Gesture
    let rotation = Float(gesture.rotation)

    //2. If The Gesture State Has Changed Set The Nodes EulerAngles.y
    if gesture.state == .changed{
        isRotating = true
        currentNode.eulerAngles.y = currentAngleY + rotation
    }

    //3. If The Gesture Has Ended Store The Last Angle Of The Cube
    if(gesture.state == .ended) {
        currentAngleY = currentNode.eulerAngles.y
        isRotating = false
    }
}

这只是一个非常粗略的示例,你需要查看不同的gestureStates等,但希望它能指引你朝着正确的方向...


1
它正在工作!非常感谢。但是如果在AR场景中有两个或更多节点,我该如何检测哪个节点正在使用手势与“currentNode”变量一起工作? - Duc Phan
我尝试使用,但有时无法移动或旋转。 - dungtv
@dungtv 记得把两个手指放得足够接近,以帮助应用程序识别您的手势是旋转手势,而不是其他手势。 https://developer.apple.com/documentation/uikit/uirotationgesturerecognizer - Khoa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接