【问题标题】:SceneKit - Adding drift to a sphere rotated via a pan gestureSceneKit - 向通过平移手势旋转的球体添加漂移
【发布时间】:2016-05-17 17:16:16
【问题描述】:

我正在使用 SceneKit,并允许用户使用平移手势旋转他们在球体内看到的内容。这工作正常 - 除了,我想让球体在平移手势的方向上保持轻微旋转,感觉更有反应。

这是我的场景设置:

    // Create scene
    let scene = SCNScene()

    sceneView.scene = scene

    let panRecognizer = UIPanGestureRecognizer(target: self,
                                               action: #selector(ViewController.handlePanGesture(_:)))

    sceneView.addGestureRecognizer(panRecognizer)

    //Create sphere
    let sphere = SCNSphere(radius: 50.0)

    // sphere setup

    sphereNode = SCNNode(geometry: sphere)

    sphereNode!.position = SCNVector3Make(0,0,0)
    scene.rootNode.addChildNode(sphereNode!)

    // Create camera
    let camera = SCNCamera()

    // camera setup

    cameraNode = SCNNode()

    cameraNode!.camera = camera
    cameraNode!.position = SCNVector3Make(0, 0, 0)

    cameraOrbit = SCNNode()

    cameraOrbit!.addChildNode(cameraNode!)
    scene.rootNode.addChildNode(cameraOrbit!)

    let lookAtConstraint = SCNLookAtConstraint(target: sphereNode!)
    lookAtConstraint.gimbalLockEnabled = true
    cameraNode!.constraints = [lookAtConstraint]

    sceneView.pointOfView = cameraNode

以下是当前处理平移手势的方式(由SCNCamera limit arcball rotation 提供):

    let translation = sender.translationInView(sender.view!)
    let widthRatio = Float(translation.x) / Float(sender.view!.frame.size.width) + lastWidthRatio
    let heightRatio = Float(translation.y) / Float(sender.view!.frame.size.height) + lastHeightRatio

    self.cameraOrbit?.eulerAngles.y = Float(-2 * M_PI) * widthRatio
    self.cameraOrbit?.eulerAngles.x = Float(-M_PI) * heightRatio

    if (sender.state == .Ended) {
        lastWidthRatio = widthRatio
        lastHeightRatio = heightRatio
    }

我不知道从哪里开始添加轻微的持续旋转动作。也许添加physicsBody 并施加力量?也许动画eulerAngles 的变化?

【问题讨论】:

    标签: ios scenekit


    【解决方案1】:

    我之前处理此类事情的方式是将手势处理程序拆分为手势状态开始、更改和结束的部分。如果轮换对您有用,您只需在 if (sender.state == .Ended) 语句的底部添加代码即可。

    lastHeightRatio = heightRatio之后,你可以使用sender.velocityInView(sender.view!)在视图中找到平移的速度,然后像以前一样找到水平分量,然后添加SCNAction以使用EaseOut计时模式旋转节点。

    您可能需要一个乘数来将视图中的速度(以点为单位)转换为您希望旋转的角度(以弧度为单位)。相对较小的 10 个点的速度会导致非常快的旋转。

    此外,如果您想通过触摸停止剩余旋转,则需要在手势再次开始时从节点中删除所有操作。

    一些示例代码是:

    if (sender.state == .Ended) {
      lastWidthRatio = widthRatio
      lastHeightRatio = heightRatio
    
      // Find velocity
      let velocity = sender.velocityInView(sender.view!)
    
      // Create Action for whichever axis is the correct one to rotate about.
      // The 0.00001 is just a factor to provide the rotation speed to pan
      // speed ratio you'd like. Play with this number and the duration to get the result you want
      let rotate = SCNAction.rotateByX(velocity.x * 0.00001, y: 0, z: 0, duration: 2.0)
    
      // Run the action on the camera orbit node (if I understand your setup correctly)
      cameraOrbit.runAction(rotate)
    }
    

    这应该足以让您入门。

    【讨论】:

    • 我最终做了类似的事情 - 谢谢!我现在的问题是lastRatio 值现在关闭,因为球体的最终静止位置比上次设置该值时旋转得更远。因此,当用户进行下一个平移手势时,相机“跳”到漂移开始之前的位置,因为eulerAngles 被重置。如果您对此有任何想法,我会全力以赴。
    • 嗯,也许尝试向runAction 添加一个完成处理程序,以便在操作完成时再次更新 lastRatio 值?
    • @AndyHeard 我试过了,但它不起作用,我真的不明白为什么。这是我的代码 sn-p lastWidthRatio += (((-velocity.x * 0.001)*2) / sender.view.frame.size.width);
    猜你喜欢
    • 2018-03-15
    • 2018-07-17
    • 2015-10-11
    • 2017-11-30
    • 2016-05-13
    • 2018-02-09
    • 1970-01-01
    • 2018-07-29
    • 2016-11-14
    相关资源
    最近更新 更多