2016-10-13 3 views
1

目的は、シーン内の任意の、しかし目に見える点を回ることです。SceneKit:カメラがジャンプしたり、アンカーポイントを中央に移動したりせずに、任意のポイント周りを回る?

ユーザがパンすると、カメラはこのアンカーポイントを中心に移動して回転する必要があります。

これは、アンカーポイントが画面の中央にある場合にうまく機能します。

ただし、アンカーポイントが中心からずれている場合(たとえば、画面の左端にある場合)、アンカーポイントが中央に来るとカメラが一時的にジャンプします。

以下のコードは、ジャンプの問題を修正しましたが、アンカーポイントがゆっくりと中央に移動するという点でユーザーに不快感を与えます。

カメラの動きがパンのジェスチャーに接続されています。

どのようにこの問題を解決するためのアイデアですか?

let panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(didSceneViewPanOneFinger)) 
panRecognizer.minimumNumberOfTouches = 1 
panRecognizer.maximumNumberOfTouches = 1 
panRecognizer.delegate = self 
sceneView.addGestureRecognizer(panRecognizer) 


func didSceneViewPanOneFinger(_ sender: UIPanGestureRecognizer) { 
    // Pick any visible point as long as it's not in center 
    let anchorPoint = SCNVector(-15, 0, 0) 

    // Orbit camera 
    cameraNode.orbitPoint(anchorPoint: anchorPoint, translation: sender.translation(in: sender.view!), state: sender.state) 
} 


class CameraNode: SCNNode { 
    // Vars 
    let headNode = SCNNode() 
    var curXRadians = Float(0) 
    var curYRadians = Float(0) 
    var directLastTranslationY = Float(0) 
    var reach = Float(10) 
    var aimingPoint = SCNVector3() 
    var lastAnchor:SCNVector3! 


    init(reach: Float) { 
     super.init() 
     self.reach = reach 

     // Call <doInit> only after all properties set 
     doInit() 
    } 


    fileprivate func doInit() { 
     // Add head node 
     headNode.camera = SCNCamera() 
     headNode.camera!.zNear = Double(0.1) 
     headNode.position = SCNVector3(x: 0, y: 0, z: 0) 
     addChildNode(headNode) 

     // Position camera 
     position = SCNVector3(x: 0, y: minY, z: reach) 
    }  


    func orbitPoint(anchorPoint: SCNVector3, translation: CGPoint, state: UIGestureRecognizerState) { 
     // Get pan distance & convert to radians 
     var xRadians = GLKMathDegreesToRadians(Float(translation.x)) 
     var yRadians = GLKMathDegreesToRadians(Float(translation.y)) 

     // Get x & y radians, adjust values to throttle rotate speed 
     xRadians = (xRadians/3) + curXRadians 
     yRadians = (yRadians/3) + curYRadians 

     // Limit yRadians to prevent rotating 360 degrees vertically 
     yRadians = max(Float(-M_PI_2), min(Float(M_PI_2), yRadians)) 

     // Save original position 
     if state == .began { 
      aimingPoint = lastAnchor ?? anchorPoint 
     } else { 
      aimingPoint = SCNVector3.lerp(vectorStart: anchorPoint, vectorEnd: aimingPoint, t: 0.99) 
     } 

     // Rotate around <anchorPoint> 
     // * Compute distance to <anchorPoint>, used as radius for spherical movement 
     let radius = aimingPoint.distanceTo(position) 
     var newPoint = getPointOnSphere(aimingPoint, hAngle: yRadians, vAngle: xRadians, radius: radius) 
     if newPoint.y < 0 { 
      yRadians = directLastTranslationY 

      newPoint = getPointOnSphere(aimingPoint, hAngle: yRadians, vAngle: xRadians, radius: radius) 
     } 

     // Set rotation values to avoid Gimbal Lock 
     headNode.rotation = SCNVector4(x: 1, y: 0, z: 0, w: yRadians) 
     rotation = SCNVector4(x: 0, y: 1, z: 0, w: xRadians) 

     print("cam pos: \(position). anchor point: \(anchorPoint). radius: \(radius).") 

     // Save value for next rotation? 
     if state == .ended { 
      curXRadians = xRadians 
      curYRadians = yRadians 
      lastAnchor = aimingPoint ?? anchorPoint 
     } 
     directLastTranslationY = yRadians 
    } 


    // Your position in 3d is given by two angles (+ radius, which in your case is constant) 
    // here, s is the angle around the y-axis, and t is the height angle, measured 'down' from the y-axis. 
    func getSphericalCoords(_ s: Float, t: Float, r: Float) -> SCNVector3 { 
     return SCNVector3(-(cos(s) * sin(t) * r), 
          sin(s) * r, 
          -(cos(s) * cos(t) * r)) 
    } 


    fileprivate func getPointOnSphere(_ centerPoint: SCNVector3, hAngle: Float, vAngle: Float, radius: Float? = nil) -> SCNVector3 { 
     // Update <radius>? 
     var radius = radius 
     if radius == nil { 
      radius = reach 
     } 

     // Compute point & return result 
     let p = centerPoint - getSphericalCoords(hAngle, t: vAngle, r: radius!) 
     return p 
    } 
} 
+0

あなたがこれで行くhow'd? – Confused

答えて

1

あなたがカメラの視野の中心ではありませんポイントを中心にカメラを回転させ、およびビューの中心にありません、その点を維持したい場合は、制約の三角配列を使用してオフに最高です。

カメラのビューの中央で、回転点に隣接して、カメラの「参照」制約として使用されるダミーオブジェクトを修正します。このダミーオブジェクトは回転点に貼り付けられているため、カメラは望みどおりに回転します。

私は、この図は私の言葉よりも優れて説明願っています:

enter image description here

+0

これは私にはたくさんの三角形のように見えます.... – Fluidity

+0

いいえ、それはダミーのオブジェクトに対して、そして次にrotationPointというノードへの制約です。数学は必要ありません。数学が必要な場合、私はそれをすることができませんでした! @Fluidity – Confused

+0

の制約は、SpriteKitとSceneKit固定接続(ほとんど)です。彼らは物事を一緒にロックし、位置関係を作成するために多少役立ちます... @Fluidity – Confused

関連する問題