使用多个UIPanGestureRecognizers旋转SceneKit立方体

4

感谢您查看此内容。我相信这是非常基础的东西。我是个初学者。

我正在尝试使用手势旋转SceneKit视图中的一个立方体。到目前为止,我已经成功地将此示例应用程序加载到我的iPad上,并沿着屏幕的y轴滑动手指以使立方体绕其x轴旋转,或者沿着屏幕的x轴滑动手指以使立方体沿其y轴旋转。

目前,我注意到无论添加到sceneView中的手势识别器是哪一个,都是有效的。我的问题是如何使立方体响应于x平移手势然后再是y平移手势或者反过来

以下是我目前编写的代码:

import UIKit
import SceneKit

class ViewController: UIViewController {

  //geometry
  var geometryNode: SCNNode = SCNNode()

  //gestures
  var currentYAngle: Float = 0.0
  var currentXAngle: Float = 0.0

  override func viewDidLoad() {
    super.viewDidLoad()

    sceneSetup()  
  }

  func sceneSetup () {
    //setup scene
    let scene = SCNScene()
    let sceneView = SCNView(frame: self.view.frame)
    self.view.addSubview(sceneView)

    //add camera
    let camera = SCNCamera()
    let cameraNode = SCNNode()
    cameraNode.camera = camera
    cameraNode.position = SCNVector3(x: 0.0, y: 0.0, z: 5.0)

    //add light
    let light = SCNLight()
    light.type = SCNLightTypeOmni
    let lightNode = SCNNode()
    lightNode.light = light
    lightNode.position = SCNVector3(x: 1.5, y: 1.5, z: 1.5)

    //add cube
    let cubeGeometry = SCNBox(width: 1.0, height: 1.0, length: 1.0, chamferRadius: 0.0)
    let boxNode = SCNNode(geometry: cubeGeometry)

    scene.rootNode.addChildNode(lightNode)
    scene.rootNode.addChildNode(cameraNode)
    scene.rootNode.addChildNode(boxNode)

    geometryNode = boxNode

    //add recognizers
    let panXRecognizer = UIPanGestureRecognizer(target: self, action: "rotateXGesture:")
    let panYRecognizer = UIPanGestureRecognizer(target: self, action: "rotateYGesture:")
    sceneView.addGestureRecognizer(panXRecognizer)
    sceneView.addGestureRecognizer(panYRecognizer)

    sceneView.scene = scene
  }

  func rotateXGesture (sender: UIPanGestureRecognizer) {
    let translation = sender.translationInView(sender.view)
    var newXAngle = (Float)(translation.y)*(Float)(M_PI)/180.0
    newXAngle += currentXAngle

    geometryNode.transform = SCNMatrix4MakeRotation(newXAngle, 1, 0, 0)

    if(sender.state == UIGestureRecognizerState.Ended) {
      currentXAngle = newXAngle
    }
  }

  func rotateYGesture (sender: UIPanGestureRecognizer) {
    let translation = sender.translationInView(sender.view)
    var newYAngle = (Float)(translation.x)*(Float)(M_PI)/180.0
    newYAngle += currentYAngle

    geometryNode.transform = SCNMatrix4MakeRotation(newYAngle, 0, 1, 0)

    if(sender.state == UIGestureRecognizerState.Ended) {
      currentYAngle = newYAngle
    }
  }
}
2个回答

9

将你现在的两个手势合并成一个。这是我正在使用的代码的相关部分:

func panGesture(sender: UIPanGestureRecognizer) {
    let translation = sender.translationInView(sender.view!)

    var newAngleX = (Float)(translation.y)*(Float)(M_PI)/180.0
    newAngleX += currentAngleX
    var newAngleY = (Float)(translation.x)*(Float)(M_PI)/180.0
    newAngleY += currentAngleY

    baseNode.eulerAngles.x = newAngleX
    baseNode.eulerAngles.y = newAngleY

    if(sender.state == UIGestureRecognizerState.Ended) {
        currentAngleX = newAngleX
        currentAngleY = newAngleY
    }
}

这里还有一个缩放手势:

func pinchGesture(sender: UIPinchGestureRecognizer) {
    let zoom = sender.scale
    var z = cameraNode.position.z  * Float(1.0 / zoom)
    z = fmaxf(zoomLimits.min, z)
    z = fminf(zoomLimits.max, z)

    cameraNode.position.z = z
}

编辑:我找到了更好的旋转模型的方法。在顶部的panGesture代码中,x轴随着你围绕y轴旋转而旋转。这意味着如果你围绕y轴旋转180度,围绕x轴的旋转方向与你的手指运动相反。该方法还将运动限制为两个自由度。下面链接的方法,即使它不直接影响z轴,也似乎允许三个自由度。它还使所有垂直滑动以逻辑方向围绕x轴旋转。 如何使用pan手势旋转场景中的对象-SceneKit


谢谢!我很兴奋尝试将两个平移手势合并为一个函数。 - brickm
我只是想跟进并说,当我在我的iPad上运行它并拖动手指左/右和上/下时,这段代码完美地工作了! - brickm
这是我做的一个快速演示。除了旋转之外,我还添加了一个平移手势来移动立方体。平移手势使用一根手指,旋转手势使用两根手指。 - brickm
我也添加了一个缩放手势。如果你还没有的话,你需要添加一个相机。 - bpedit

1
你设置两个手势识别器的方式是相同的,它们都会对相同的事件进行触发(这就是为什么最后添加的手势识别器占主导地位)。在pan中没有特定的控制来限制垂直或水平pan。相反,考虑分析pan的方向,然后根据哪个更大来决定是否将手势旋转一侧或另一侧。

谢谢!这很有帮助。我得开始寻找分析平移方向的示例。 - brickm

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