2016-05-16 39 views
2

我正在使用SceneKit並允許用戶使用平移手勢旋轉他們在球體內看到的內容。這工作正常 - 除了我想讓球體在平移手勢的方向上稍微旋轉一點,感覺更加反應一點。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的變化?

回答

4

我之前處理過的事情的方式是將手勢處理程序分爲手勢狀態開始,更改和結束的部分。如果輪換正在爲您工作,您只需將代碼添加到if (sender.state == .Ended)聲明的底部。

lastHeightRatio = heightRatio之後,可以使用sender.velocityInView(sender.view!)找到在視圖中鍋的速度,然後找到的水平分量爲前,再加入一個SCNAction旋轉與EaseOut定時模式的節點。

您可能需要乘數來將視圖中的速度(以點爲單位)轉換爲您希望旋轉的角度(以弧度爲單位)。 10點的速度相對較小,會導致非常快速的旋轉。

如果您想要觸摸來停止剩餘旋轉,則還需要在手勢再次開始時從節點中刪除所有操作。

一些sampel代碼如下:

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

這應該足以讓你開始。

+0

我最終做了類似的事情 - 謝謝!我現在的問題是'lastRatio'值現在已關閉,因爲球體的最終靜止位置比最後一次設置的值旋轉得更遠。因此,當用戶進行下一個平移手勢時,隨着「eulerAngles」被重置,相機「跳」到漂移開始之前的位置。如果你對這個問題有任何想法,我就會全神貫注。 –

+0

嗯,也許嘗試添加一個完成處理程序到'runAction',當動作完成時再次更新lastRatio值? –

+0

@AndyHeard我嘗試過,但它不工作,我真的不明白爲什麼。這裏是我的代碼片段'''lastWidthRatio + =(((--velocity.x * 0.001)* 2)/ sender.view.frame.size.width);''' –