2016-08-08 45 views
1

Ich muss auf bestimmte Knoten, zum Beispiel eine Pyramide konzentrieren. Wenden Sie dann die Entfernung auf die Kamera an und bewegen Sie dann die Kamera basierend auf dem Klick des Benutzers. Mein Ansatz ist wie folgt aus:SCNCamera bewegliche Kamera Pivot

import SceneKit 

class GameViewController: UIViewController { 
let scene = SCNScene() 
override func viewDidLoad() { 
    super.viewDidLoad() 
    let camera = SCNCamera() 
    camera.usesOrthographicProjection = true 
    camera.orthographicScale = 4 
    camera.zNear = 1 
    camera.zFar = 100 
    let cameraNode = SCNNode() 
    cameraNode.position = SCNVector3(x: 0, y: 0, z: 6) 
    cameraNode.camera = camera 
    let cameraOrbit = SCNNode() 
    cameraOrbit.name = "orbit" 
    cameraOrbit.addChildNode(cameraNode) 
    scene.rootNode.addChildNode(cameraOrbit) 

    let Py = SCNPyramid(width: 2, height: 3, length: 2) 
    Py.firstMaterial?.diffuse.contents = UIColor.purple() 
    let P = SCNNode(geometry: Py) 
    P.position = SCNVector3(x:0,y:0,z:2) //see the note 
    scene.rootNode.addChildNode(P) 

    /* N O T E : 
    the position of the pyramid must not be changed 
    as my intention is to rotate the camera 
    not the pyramid node 
    I repeat, I don't want to rotate the pyramid 
    */ 

    let scnView = self.view as! SCNView 
    scnView.scene = scene 
    scnView.allowsCameraControl = false 
    scnView.backgroundColor = UIColor.black() 

    // user rotates the camera by tapping 
    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:))) 
    scnView.addGestureRecognizer(tapGesture) 
} 


//the function which does camera rotation : 
func handleTap(_ gestureRecognize: UIGestureRecognizer) { 
    //I guess the solution is around here 
    //like modify the cameraOrbit.position ? 
    //or cameraNode.position ? 
    //tried both but doesn't work 
    //or I used them wrong 
    let cameraOrbit = scene.rootNode.childNode(withName: "orbit", recursively: true)! 
    SCNTransaction.begin() 
    SCNTransaction.animationDuration = 2 
    cameraOrbit.eulerAngles.z += Float(M_PI_2) //see below 
    SCNTransaction.commit() 
    /* 
    I realise that by performing rotation on the camera 
    (the camera position is unchanged) works for z rotation, 
    but this is not what I want. What I want is a solution, 
    which also works for eulerAngles.x and eulerAngles.y. 

    I used eulerAngles.z as example since it's easier to observe. 

    I guess the true solution involves moving the camera 
    with specific trajectory, not only rotation of "anchored" camera. 
    */ 
    } 

//... 
} 

Das Ergebnis ist:

the triangle rotates around a point below the apex

Was ich erreichen will, ist die Drehung relativ zu seiner Mitte zu machen:

like this

Meine Frage ist, wie kann ich den Drehpunkt so einstellen, dass ich die Drehung relativ zum Zentrum der Pyramide erreichen kann?

Hinweis: Ich möchte die Pyramide nicht drehen.

Antwort

0

Ich fand die Lösung, aber ich kann nicht erklären warum. Bitte kommentieren Sie, wenn Sie es erklären können.

Die Kameraposition muss auf die Position des Objekts (in diesem Fall die Pyramide) eingestellt werden. So

cameraOrbit.position = P.position 

Dann kommt hier die Rätsels Lösung, fügen cameraOrbit.position.y um die Hälfte von pi:

cameraOrbit.position.y += Float(M_PI_2) 
//therefore we have the final cameraOrbit.position as (0, pi/2, 2) 

Getestet und funktioniert perfekt für alle cameraOrbit.eulerAngles. Aber ich habe keine Ahnung, warum es funktioniert. Wenn pi/2 von einem Projektions-Ding kommt, warum versteckt es sich dann nur? Ich meine, wenn ich irgendeinen der cameraOrbit.eulerAngles mache, muss ich diesen Pi/2 weder x noch z zuweisen.

Hier ist es der vollständige Code

import SceneKit 

class GameViewController: UIViewController { 
let scene = SCNScene() 
override func viewDidLoad() { 
    super.viewDidLoad() 
    let camera = SCNCamera() 
    camera.usesOrthographicProjection = true 
    camera.orthographicScale = 4 
    camera.zNear = 1 
    camera.zFar = 100 
    let cameraNode = SCNNode() 
    cameraNode.position = SCNVector3(x: 0, y: 0, z: 6) 
    cameraNode.camera = camera 
    let cameraOrbit = SCNNode() 
    cameraOrbit.name = "orbit" 
    cameraOrbit.addChildNode(cameraNode) 
    scene.rootNode.addChildNode(cameraOrbit) 

    let Py = SCNPyramid(width: 2, height: 3, length: 2) 
    Py.firstMaterial?.diffuse.contents = UIColor.purple() 
    let P = SCNNode(geometry: Py) 
    P.position = SCNVector3(x:0,y:0,z:2) 
    scene.rootNode.addChildNode(P) 

    // S O L U T I O N : 
    cameraOrbit.position = P.position 
    cameraOrbit.position.y += Float(M_PI_2) 
    //therefore we have the final cameraOrbit.position as (0, pi/2, 2) 

    let scnView = self.view as! SCNView 
    scnView.scene = scene 
    scnView.allowsCameraControl = false 
    scnView.backgroundColor = UIColor.black() 

    // user rotates the camera by tapping 
    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:))) 
    scnView.addGestureRecognizer(tapGesture) 
} 

//the function which does camera rotation : 
func handleTap(_ gestureRecognize: UIGestureRecognizer) { 
    //I was wrong, the solution is not here 
    let cameraOrbit = scene.rootNode.childNode(withName: "orbit", recursively: true)! 
    SCNTransaction.begin() 
    SCNTransaction.animationDuration = 2 
    cameraOrbit.eulerAngles.z += Float(M_PI_2) //works also for x and y 
    SCNTransaction.commit() 

    } 

... 
}