2016-10-13 4 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

이 와은 어떻게 되가요? – Confused

답변

1

, 당신은 제약의 삼각형 배열을 사용하는 것이 가장 좋은 선택입니다.

카메라 시점의 중심에서 회전 지점 근처에서 카메라의 "보기"제약 조건으로 사용되는 더미 개체를 수정합니다. 이 더미 오브젝트는 회전 지점에 고정되어 있으므로 원하는대로 카메라가 회전합니다.

나는이 그림은 내 말보다 더 설명하겠습니다 :

enter image description here

+0

이것은 나에게 많은 트릭처럼 보입니다 .... – Fluidity

+0

아니요, 더미 오브젝트에 대한 제약 조건이며, 다음은 rotationPoint 노드입니다. 수학은 필요하지 않습니다. 수학이 필요하다면 할 수 없었습니다! @Fluidity – Confused

+0

제약 조건은 SpriteKit 및 SceneKit 고정 연결입니다 (대부분). 그들은 일을 함께 묶고 위치 관계를 만드는 데 다소 유용합니다 ... @Fluidity – Confused

관련 문제