首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用平移手势识别器旋转SCNSphere

如何使用平移手势识别器旋转SCNSphere
EN

Stack Overflow用户
提问于 2017-08-24 09:39:02
回答 2查看 1.6K关注 0票数 3

我创建了一个SCNSphere,所以现在它看起来有点像行星。这正是我想要的。我的下一个目标是允许用户使用平移手势识别器旋转球体。他们可以绕X或Y轴旋转它。我只是想知道我怎么才能做到。这就是我到目前为止所拥有的。

代码语言:javascript
复制
origin = sceneView.frame.origin
node.geometry = SCNSphere(radius: 1)
node.geometry?.firstMaterial?.diffuse.contents = UIImage(named: "world.jpg")

let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(CategoryViewController.panGlobe(sender:)))
sceneView.addGestureRecognizer(panGestureRecognizer)

func panGlobe(sender: UIPanGestureRecognizer) {
    // What should i put inside this method to allow them to rotate the sphere/ball
}
EN

回答 2

Stack Overflow用户

发布于 2017-08-24 20:41:55

我们有一个包含节点sphereNode的ViewController,该节点包含我们的球体。要旋转球体,我们可以使用UIPanGestureRecognizer。由于识别器报告我们的手指在屏幕上移动的总距离,因此我们缓存了报告给我们的最后一个点。

代码语言:javascript
复制
var previousPanPoint: CGPoint?
let pixelToAngleConstant: Float = .pi / 180
func handlePan(_ newPoint: CGPoint) {
    if let previousPoint = previousPanPoint {
        let dx = Float(newPoint.x - previousPoint.x)
        let dy = Float(newPoint.y - previousPoint.y)

        rotateUp(by: dy * pixelToAngleConstant)
        rotateRight(by: dx * pixelToAngleConstant)
    }

    previousPanPoint = newPoint
}

我们使用自上次调用识别器以来手指在每个方向上移动了多少像素来计算dxdy。使用pixelToAngleConstant,我们将像素值转换为一个角度(以randians为单位)以旋转球体。使用较大的常量可加快旋转速度。

手势识别器返回一个state,我们可以使用它来确定手势是否已开始、结束或手指是否已移动。当手势开始时,我们将手指位置保存在previousPanPoint中。当我们的手指移动时,我们调用上面的函数。当手势结束或取消时,我们清除我们的previousPanPoint

代码语言:javascript
复制
@objc func handleGesture(_ gestureRecognizer: UIPanGestureRecognizer) {
    switch gestureRecognizer.state {
    case .began:
        previousPanPoint = gestureRecognizer.location(in: view)
    case .changed:
        handlePan(gestureRecognizer.location(in: view))
    default:
        previousPanPoint = nil
    }
}

我们如何旋转球体?函数rotateUprotateRight只是调用我们更一般的函数rotate(by: around:),它不仅接受角度,还接受旋转的轴。rotateUp绕x轴旋转,rotateRight绕y轴旋转。

代码语言:javascript
复制
func rotateUp(by angle: Float) {
    let axis = SCNVector3(1, 0, 0) // x-axis
    rotate(by: angle, around: axis)
}

func rotateRight(by angle: Float) {
    let axis = SCNVector3(0, 1, 0) // y-axis
    rotate(by: angle, around: axis)
}

在这种情况下,rotate(by:around:)是相对简单的,因为我们假设节点没有被平移/我们希望围绕节点的原点旋转局部坐标系。当我们看一般情况时,一切都有点复杂,但这个答案只是一个很小的起点。

代码语言:javascript
复制
func rotate(by angle: Float, around axis: SCNVector3) {
    let transform = SCNMatrix4MakeRotation(angle, axis.x, axis.y, axis.z)
    sphereNode.transform = SCNMatrix4Mult(sphereNode.transform, transform)
}

我们从angleaxis创建一个旋转矩阵,然后将球体的旧transform与计算出的transform相乘,得到新的transform

这是我创建的小演示:

这种方法有两个主要的缺点。

仅当节点的位置为SCNVector3Zero

  • It时,它才会围绕节点坐标原点旋转。
  1. 不考虑手势的速度,也不会在手势停止时球体继续旋转。使用这种方法很难实现类似于表格视图的效果,在表格视图中,您可以翻转手指,表格视图快速滚动,然后减慢滚动速度。一种解决方案是使用物理系统来解决这个问题。
票数 4
EN

Stack Overflow用户

发布于 2018-04-11 11:36:23

下面是我尝试过的,不确定它在角度方面是否准确,but...it满足了我的大部分需求……

代码语言:javascript
复制
@objc func handleGesture(_ gestureRecognizer: UIPanGestureRecognizer) {

    let translation = gestureRecognizer.translation(in: gestureRecognizer.view!)

    let x = Float(translation.x)
    let y = Float(-translation.y)
    let anglePan = (sqrt(pow(x,2)+pow(y,2)))*(Float)(Double.pi)/180.0

    var rotationVector = SCNVector4()
    rotationVector.x = x
    rotationVector.y = y
    rotationVector.z = 0.0
    rotationVector.w = anglePan


    self.earthNode.rotation = rotationVector
}

示例Github-EarthRotate

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45851641

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档