2016-08-08 2 views
1

Мне нужно сфокусироваться на определенном узле, например на пирамиде. Затем примените расстояние до камеры, затем переместите камеру на основе щелчка пользователя. Мой подход таков:SCNCamera движущаяся ось камеры

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. 
    */ 
    } 

//... 
} 

Результат:

the triangle rotates around a point below the apex

То, что я хочу добиться того, чтобы сделать поворот относительно его центра:

like this

Мой вопрос в том, как настроить ось вращения, чтобы я мог достичь вращения относительно центра пирамиды?

Примечание: я не хочу вращать пирамиду.

ответ

0

Я нашел решение, но не могу объяснить, почему. Прошу прокомментировать, если вы можете объяснить.

Позиция орбиты камеры должна быть установлена ​​в соответствии с местоположением объекта (в данном случае пирамиды). Так

cameraOrbit.position = P.position 

Тогда здесь приходит решение тайна, добавить cameraOrbit.position.y на половину пи:

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

протестирована и работает отлично для всех cameraOrbit.eulerAngles. Но у меня нет подсказки, почему это работает. Если pi/2 исходит от какой-то проекции, то почему он заправлен только на y? Я имею в виду, что когда я делаю какой-либо из камерных объектов. Мне не нужно назначать этот pi/2 либо x, либо z.

Здесь полный код

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() 

    } 

... 
} 
Смежные вопросы