2015-11-28 7 views
8

私は、SCNCameraを使ってシーンの周りを回転するシーン設定をしています。SCNCカメラリミットアークボール回転

カメラがオブジェクトの周りを回転できる範囲を制限するにはどうすればよいでしょうか?

例:球全体を回転するのではなく、回転を単一の半球に制限するにはどうすればよいですか?

初めての試みは、.allowsCameraControlのクランプがあるかどうかを確認することでした。何も見つかりませんでした。

次に、C#Unity:mouse orbit script、no luckを適応させてみました。

これにアプローチする方法や解決する方法についてのいくつかの指針は素晴らしいでしょう。

定型アークボールthis answer.

var lastWidthRatio: Float = 0 
var lastHeightRatio: Float = 0 

let camera = SCNCamera() 
let cameraNode = SCNNode() 
let cameraOrbit = SCNNode() 

override func viewDidLoad() { 
    super.viewDidLoad() 

    // create a new scene 
    let scene = SCNScene(named: "art.scnassets/ship.scn")! 

    // create and add a camera to the scene 

    camera.usesOrthographicProjection = true 
    camera.orthographicScale = 9 
    camera.zNear = 0 
    camera.zFar = 100 

    cameraNode.position = SCNVector3(x: 0, y: 0, z: 50) 
    cameraNode.camera = camera 

    cameraOrbit.addChildNode(cameraNode) 
    scene.rootNode.addChildNode(cameraOrbit) 

    // retrieve the ship node 
    let ship = scene.rootNode.childNodeWithName("ship", recursively: true)! 

    // retrieve the SCNView 
    let scnView = self.view as! SCNView 

    // set the scene to the view 
    scnView.scene = scene 

    // add a tap gesture recognizer 
    let gesture = UIPanGestureRecognizer(target: self, action: "panDetected:"); 
    scnView.addGestureRecognizer(gesture); 
} 


func panDetected(sender: UIPanGestureRecognizer) { 
    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 

    print(Float(-2 * M_PI) * widthRatio) 
    if (sender.state == .Ended) { 
     lastWidthRatio = widthRatio % 1 
     lastHeightRatio = heightRatio % 1 
    } 
} 
+1

モジュラス1の操作では、望む結果( 'widthRatio%1')はほとんどないと思います。 widthRatioは-1から1まで変化しますが、ユーザーが制限を超えて回転すると、値は-0.9から-1.2に変更される可能性があります。モジュラスが適用され、0.2の値が得られ、球の反対側に突然ジャンプします。 値が-1より小さい場合は2を加算し、回転の終了が1より大きい場合は2を減算することです。その方法を使用すると、-0.9の位置から-1.2の値に移動すると値0.8の値が得られました。 –

答えて

4

のおかげで、あなたはほとんどそこにいるようにそれはあなたが引用 答えからちょうど@Ricksterコードを使用して、見えます。あなたが作ることができる

の変化は、これらの行に次のようになります。暗黙的にピッチとヨーは全体 球をカバーすることができ

self.cameraOrbit.eulerAngles.y = Float(-2 * M_PI) * widthRatio 
self.cameraOrbit.eulerAngles.x = Float(-M_PI) * heightRatio 

。それがあなたの制限を行うことができる場所です。例えば、 代わりのピッチ(eulerAngles.x)が-π0 から変化させることは、に全画面を 垂直スクロールを使用して、-π/ 2と-πの間で滑らかに変化する

self.cameraOrbit.eulerAngles.x = Float(-M_PI_2) + Float(-M_PI_2) * heightRatio 

を行うことができその範囲をカバーする。または、 ハード/最小制限/チェックをそれらの2つの行に入れて、 を地球の特定の領域に制限することができます。

(慣性コメントに対処するための編集)回転減衰、または慣性のために

、私はSceneKit物理学で構築を使用して、それに近づく、そしておそらく目に見えない(なし形状)にカメラを置くところSCNNode。そのカメラノードはジンバルになります。これはこのプロジェクトで採用されているアプローチと同じです:An interactive seven-foot globe created entirely in RubyMotion and SceneKit

バーチャルジンバルは、SCNPhysicsBody(デフォルトでは1つではありません)を追加します。dampingです。あるいは、物理オブジェクトを中央オブジェクトに置き、そのオブジェクトに何かangularDampingを与えることもできます。

+0

あなたには非常に感謝しています。私があなたの変更を入れて、アングルからプリントを見た後、それはすべて意味があり、クリックされました。 – Magrafear

+0

できるだけ@ hal-muellerという質問がありますか?アークボールの回転に慣性を加えようとしています。 'せて回転= SCNAction.rotateByAngle(CGFloat(フロート(-M_PI_2)+フロート(-M_PI_2)* widthRatio)、aroundAxis:SCNVector3Make(0 、0、1)、持続時間:NSTimeInterval(1)) ' 私が一番近いのは、それが正しいことです。しかし、ターンはそれが見えるアークの周りを回らない。ありがとう – Magrafear

4

おそらく、これは読者にとって役に立ちます。

class GameViewController: UIViewController { 

    var cameraOrbit = SCNNode() 
    let cameraNode = SCNNode() 
    let camera = SCNCamera() 


    //HANDLE PAN CAMERA 
    var lastWidthRatio: Float = 0 
    var lastHeightRatio: Float = 0.2 
    var WidthRatio: Float = 0 
    var HeightRatio: Float = 0.2 
    var fingersNeededToPan = 1 
    var maxWidthRatioRight: Float = 0.2 
    var maxWidthRatioLeft: Float = -0.2 
    var maxHeightRatioXDown: Float = 0.02 
    var maxHeightRatioXUp: Float = 0.4 

    //HANDLE PINCH CAMERA 
    var pinchAttenuation = 20.0 //1.0: very fast ---- 100.0 very slow 
    var lastFingersNumber = 0 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     // create a new scene 
     let scene = SCNScene(named: "art.scnassets/ship.scn")! 

     // create and add a light to the scene 
     let lightNode = SCNNode() 
     lightNode.light = SCNLight() 
     lightNode.light!.type = SCNLightTypeOmni 
     lightNode.position = SCNVector3(x: 0, y: 10, z: 10) 
     scene.rootNode.addChildNode(lightNode) 

     // create and add an ambient light to the scene 
     let ambientLightNode = SCNNode() 
     ambientLightNode.light = SCNLight() 
     ambientLightNode.light!.type = SCNLightTypeAmbient 
     ambientLightNode.light!.color = UIColor.darkGrayColor() 
     scene.rootNode.addChildNode(ambientLightNode) 

    //Create a camera like Rickster said 
     camera.usesOrthographicProjection = true 
     camera.orthographicScale = 9 
     camera.zNear = 1 
     camera.zFar = 100 

     cameraNode.position = SCNVector3(x: 0, y: 0, z: 50) 
     cameraNode.camera = camera 
     cameraOrbit = SCNNode() 
     cameraOrbit.addChildNode(cameraNode) 
     scene.rootNode.addChildNode(cameraOrbit) 

     //initial camera setup 
     self.cameraOrbit.eulerAngles.y = Float(-2 * M_PI) * lastWidthRatio 
     self.cameraOrbit.eulerAngles.x = Float(-M_PI) * lastHeightRatio 

     // retrieve the SCNView 
     let scnView = self.view as! SCNView 

     // set the scene to the view 
     scnView.scene = scene 

     //allows the user to manipulate the camera 
     scnView.allowsCameraControl = false //not needed 

     // add a tap gesture recognizer 
     let panGesture = UIPanGestureRecognizer(target: self, action: "handlePan:") 
     scnView.addGestureRecognizer(panGesture) 

     // add a pinch gesture recognizer 
     let pinchGesture = UIPinchGestureRecognizer(target: self, action: "handlePinch:") 
     scnView.addGestureRecognizer(pinchGesture) 
    } 

    func handlePan(gestureRecognize: UIPanGestureRecognizer) { 

     let numberOfTouches = gestureRecognize.numberOfTouches() 

     let translation = gestureRecognize.translationInView(gestureRecognize.view!) 

     if (numberOfTouches==fingersNeededToPan) { 

      widthRatio = Float(translation.x)/Float(gestureRecognize.view!.frame.size.width) + lastWidthRatio 
      heightRatio = Float(translation.y)/Float(gestureRecognize.view!.frame.size.height) + lastHeightRatio 

      // HEIGHT constraints 
      if (heightRatio >= maxHeightRatioXUp) { 
       heightRatio = maxHeightRatioXUp 
      } 
      if (heightRatio <= maxHeightRatioXDown) { 
       heightRatio = maxHeightRatioXDown 
      } 


      // WIDTH constraints 
      if(widthRatio >= maxWidthRatioRight) { 
       widthRatio = maxWidthRatioRight 
      } 
      if(widthRatio <= maxWidthRatioLeft) { 
       widthRatio = maxWidthRatioLeft 
      } 

      self.cameraOrbit.eulerAngles.y = Float(-2 * M_PI) * widthRatio 
      self.cameraOrbit.eulerAngles.x = Float(-M_PI) * heightRatio 

      print("Height: \(round(heightRatio*100))") 
      print("Width: \(round(widthRatio*100))") 


      //for final check on fingers number 
      lastFingersNumber = fingersNeededToPan 
     } 

     lastFingersNumber = (numberOfTouches>0 ? numberOfTouches : lastFingersNumber) 

     if (gestureRecognize.state == .Ended && lastFingersNumber==fingersNeededToPan) { 
      lastWidthRatio = widthRatio 
      lastHeightRatio = heightRatio 
      print("Pan with \(lastFingersNumber) finger\(lastFingersNumber>1 ? "s" : "")") 
     } 
    } 

    func handlePinch(gestureRecognize: UIPinchGestureRecognizer) { 
     let pinchVelocity = Double.init(gestureRecognize.velocity) 
     //print("PinchVelocity \(pinchVelocity)") 

     camera.orthographicScale -= (pinchVelocity/pinchAttenuation) 

     if camera.orthographicScale <= 0.5 { 
      camera.orthographicScale = 0.5 
     } 

     if camera.orthographicScale >= 10.0 { 
      camera.orthographicScale = 10.0 
     } 

    }