简体   繁体   English

SceneKit - 向通过平移手势旋转的球体添加漂移

[英]SceneKit - Adding drift to a sphere rotated via a pan gesture

I am using SceneKit and allowing users to rotate what they're seeing inside a sphere by using a pan gesture. 我正在使用SceneKit并允许用户使用平移手势旋转他们在球体内看到的内容。 This is working fine - except, I'd like to have the sphere keep rotating slightly in the direction of the pan gesture, to feel a bit more reactive. 这很好 - 除了我想让球体在摇摄手势的方向上保持稍微旋转,感觉有点反应。

Here's my setup for the scene: 这是我对场景的设置:

    // 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

And here is how the pan gesture is currently handled (courtesy of SCNCamera limit arcball rotation ): 以下是当前处理平移手势的方式(由SCNCamera限制弧形旋转提供 ):

    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
    }

I'm not sure where to begin in adding in a slight continued rotation motion. 我不知道从哪里开始添加一个轻微的持续旋转运动。 Maybe adding a physicsBody and applying force? 也许添加一个physicsBody并使用force? Maybe animating the change in eulerAngles ? 也许激活eulerAngles的变化?

The way I've handled things like this before is to split the gesture handler into sections for the gesture state beginning, changing and ending. 我以前处理这样的事情的方式是将手势处理程序分成手势状态开始,更改和结束的部分。 If the rotation is working for you all you need to do is add code to the bottom of your if (sender.state == .Ended) statement. 如果旋转对您if (sender.state == .Ended)您只需将代码添加到if (sender.state == .Ended)语句的底部。

After lastHeightRatio = heightRatio you can find the velocity of the pan in the view using sender.velocityInView(sender.view!) and then find the horizontal component as before, then add an SCNAction to rotate the node with an EaseOut timing mode. lastHeightRatio = heightRatio您可以使用sender.velocityInView(sender.view!)在视图中找到平移的速度,然后像以前一样找到水平分量,然后添加SCNAction以使用EaseOut计时模式旋转节点。

You'll likely need a multiplier to translate the velocity in the view (measured in points) to the angle you wish to rotate through (measured in radians). 您可能需要一个乘数来将视图中的速度(以点为单位)转换为您希望旋转的角度(以弧度为单位)。 A velocity of 10 points, which is relatively small, would result in a very fast rotation. 10点的速度相对较小,将导致非常快的旋转。

Also you'll need to remove all actions from the node when the gesture begins again if you want a touch to stop the residual rotation. 此外,如果您想要触摸来停止剩余旋转,则需要在手势再次开始时从节点中删除所有操作。

Some sampel code would be: 一些样本代码将是:

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)
}

This should be enough to get you started. 这应该足以让你入门。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM