[swift]SCNCamera 移动相机数据透视

标签: ios Swift
发布时间: 2017/3/6 23:08:52
注意事项: 本文中文内容可能为机器翻译,如要查看英文原文请点击上面连接.

我需要将焦点到某一节点,例如一座金字塔。适用于摄像机的距离,然后移动相机基于用户单击。我的方法是这样的︰

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

我的问题是,如何调整支点,这样我就可以实现与金字塔的中心旋转吗?

注︰ 我不想要旋转的金字塔。

解决方法 1:

我找到了解决办法,但我不能解释为什么。请评论,如果你可以解释一下。

必须设置摄像机轨道位置,以匹配对象的位置 (在本例中,金字塔)。所以

cameraOrbit.position = P.position

然后来了神秘的解决方案,通过 pi 的一半来添加 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 只?我的意思是,当我做任何的 cameraOrbit.eulerAngles,我不需要将此 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()

     }

...
}
官方微信
官方QQ群
31647020