2017-10-03 3 views
2

저는 첫 번째 장면 키트 프로젝트를 작성하고 있습니다. 팬 제스처를 사용하여 내 장면에서 간단한 오브젝트를 회전하려고합니다 (오브젝트는 .dae 파일에서 가져온 간단한 L 큐브 모양 임). , 피벗 포인트가 올바르게 설정 됨).SceneKit - 방향을 기준으로 팬 제스처로 SCNNode를 회전하십시오.

여러 SO 솔루션 및 자습서를 거쳤으며 일부 코드를 조합했지만 회전이 올바르게 작동하지 않습니다. 만약 내가 반복적으로 하나의 축을 따라 객체를 회전 시키려고한다면, 그것은 올바르게 작동하지만, 다른 방향을 시도 할 때, 팬의 시작에서 객체는 그것의 초기 위치로 재설정됩니다. 때로는 회전이 무작위로 버벅 거리거나 점프하는 경우도 있습니다. 내가 조언을 해주십시오에 대한 올바른 접근 방식을 사용하면 내가 여기에 내 코드입니다 .. 확실하지 않다 : 연구와 헤드 뱅잉 벽의 몇 시간의 LOT 후

func handlePan(sender: UIPanGestureRecognizer){ 

    // determine pan direction 
    let velocity: CGPoint = sender.velocity(in: sender.view!) 
    if self.panDirection == nil { 
     if velocity.x > 0 && velocity.x > abs(velocity.y) { self.panDirection = "right" } 
     if velocity.x < 0 && abs(velocity.x) > abs(velocity.y) { self.panDirection = "left" } 
     if velocity.y < 0 && abs(velocity.y) > abs(velocity.x) { self.panDirection = "up" } 
     if velocity.y > 0 && velocity.y > abs(velocity.x) { self.panDirection = "down" } 
    } 

    // do rotation only on selected SCNNode 
    if self.selectedBrickNode != nil { 

     // start of pan gesture 
     if sender.state == UIGestureRecognizerState.began{ 
      // remember initial rotation angle 
      self.initRot = self.selectedBrickNode.rotation.w 
     } 

     let translation = sender.translation(in: sender.view!) 
     let pan_x = Float(translation.x) 
     let pan_y = Float(-translation.y) 

     // add rotation angle to initial rotation 
     var anglePan = self.initRot + (Float)(sqrt(pow(pan_x,2)+pow(pan_y,2)))*(Float)(Double.pi)/180.0 
     var rotVector = SCNVector4() 

     // if left/right, rotate on Y axis 
     rotVector.x = (self.panDirection == "left" || self.panDirection == "right") ? 0 : -pan_y 
     // if up/down, rotate on X axis 
     rotVector.y = (self.panDirection == "up" || self.panDirection == "down") ? 0 : pan_x 
     rotVector.z = 0 
     rotVector.w = anglePan 

     // set SCNNode's rotation 
     self.selectedBrickNode.rotation = rotVector 

     // end of pan gesture 
     if(sender.state == UIGestureRecognizerState.ended) { 

      // reset initial rotation 
      self.initRot = 0.0 

      // calculate degrees so we can snap to 90deg increments 
      var angle = anglePan * (Float) (180.0/Double.pi) 

      // snap to 90deg increments 
      let diff = angle.truncatingRemainder(dividingBy: 90.0) 
      if diff <= 45 { 
       angle = angle - diff 
      }else{ 
       angle = (angle - diff) + 90 
      } 

      // set new rotation to snap 
      rotVector.w = angle * (Float)(Double.pi)/180.0 
      self.selectedBrickNode.rotation = rotVector 
      self.selectedBrickNode = nil 
     } 
    } 


} 

답변

4

, 나는 마침내 작업 솔루션을 발견 비슷한 목표를 가진 사람을 돕기를 바랍니다.

내 작업 코드 :

func handlePan(sender: UIPanGestureRecognizer){ 

    // get pan direction 
    let velocity: CGPoint = sender.velocity(in: sender.view!) 
    if self.panDirection == nil { 
     self.panDirection = GameHelper.getPanDirection(velocity: velocity) 
    } 

    // if selected brick 
    if self.selectedBrickNode != nil { 

     if sender.state == UIGestureRecognizerState.began{ 
      lastAngle = 0.0 // reset last angle 
     } 

     let translation = sender.translation(in: sender.view!) 
     let anglePan = (self.panDirection == "horizontal") ? GameHelper.deg2rad(deg: Float(translation.x)) : GameHelper.deg2rad(deg: Float(translation.y)) 

     let x:Float = (self.panDirection == "vertical") ? 1 : 0.0 
     let y:Float = (self.panDirection == "horizontal") ? 1 : 0.0 

     // calculate the angle change from last call 
     let fraction = anglePan - lastAngle 
     lastAngle = anglePan 

     // perform rotation by difference to last angle 
     selectedBrickNode.transform = SCNMatrix4Mult(selectedBrickNode.transform,SCNMatrix4MakeRotation(fraction, x, y, 0.0)) 


     if(sender.state == UIGestureRecognizerState.ended) { 

      // calculate angle to snap to 90 degree increments 
      let finalRotation = GameHelper.rad2deg(rad:anglePan) 
      let diff = finalRotation.truncatingRemainder(dividingBy: 90.0) 
      var finalDiff = Float(0.0) 

      switch diff { 
       case 45..<90 : 
        finalDiff = 90 - diff 
       case 0..<45 : 
        finalDiff = -diff 
       case -45..<0 : 
        finalDiff = abs(diff) 
       case -90 ..< -45 : 
        finalDiff = -90 - diff 
      default: 
       print("do nothing") 
      } 

      // final transform to apply snap to closest 90deg increment 
      let snapAngle = GameHelper.deg2rad(deg: finalDiff) 
      selectedBrickNode.transform = SCNMatrix4Mult(selectedBrickNode.transform, SCNMatrix4MakeRotation(snapAngle, x, y, 0.0)) 

      // remove highlight from node and deselect 
      self.selectedBrickNode?.geometry?.materials = [hlp.defaultMaterial] 
      self.selectedBrickNode = nil 
     } 
    } 


} 

및 GameHelper.swift

class GameHelper { 

    static func rad2deg(rad:Float) -> Float { 
    return rad * (Float) (180.0/Double.pi) 
    } 

    static func deg2rad(deg:Float) -> Float{ 
    return deg * (Float)(Double.pi/180) 
    } 

    static func getPanDirection(velocity: CGPoint) -> String { 
    var panDirection:String = "" 
    if (velocity.x > 0 && velocity.x > abs(velocity.y) || velocity.x < 0 && abs(velocity.x) > abs(velocity.y)){ 
     panDirection = "horizontal" 
    } 

    if (velocity.y < 0 && abs(velocity.y) > abs(velocity.x) || velocity.y > 0 && velocity.y > abs(velocity.x)) { 
     panDirection = "vertical" 
    } 


    return panDirection 
    } 

} 
관련 문제