SceneKit:使用平移手势将摄像机朝向其朝向的方向移动

时间:2018-02-19 16:36:46

标签: ios swift rotation scenekit panning

我在SceneKit游戏中设置了一些自定义相机控件。基于相机的角度,我的平移手势自动调整有问题。平移手势我通过在x和z轴上平移相机(通过使用手势平移)来解决问题是,尽管相机旋转,相机仍将在x和z轴上平移。我想要它,以便相机在轴面上平移。

这是我用来平移/旋转的手势:

平移:

var previousTranslation = SCNVector3(x: 0.0,y: 15,z: 0.0)
var lastWidthRatio:Float = 0
var angle:Float = 0

@objc func pan(gesture: UIPanGestureRecognizer) {
    gesture.minimumNumberOfTouches = 1
    gesture.maximumNumberOfTouches = 1
    if gesture.numberOfTouches == 1 {
        let view = self.view as! SCNView
        let node = view.scene!.rootNode.childNode(withName: "Node", recursively: false)
        let secondNode =  view.scene!.rootNode.childNode(withName: "CameraHandler", recursively: false)
        let translation = gesture.translation(in: view)

        let constant: Float = 30.0
        angle = secondNode!.eulerAngles.y
        //these were the previous values I was using to handle panning, they worked but provided really jittery movement. You can change the direction they rotate by multiplying the sine/cosine .pi values by any integer.
        //var translateX = Float(translation.y) * sin(.pi) / cos(.pi) - Float(translation.x) * cos(.pi)
        //var translateY = Float(translation.y) * cos(.pi) / cos(.pi) + Float(translation.x) * sin(.pi)

        //these ones work a lot smoother
        var translateX = Float(translation.x) * Float(Double.pi / 180)
        var translateY = Float(translation.y) * Float(Double.pi / 180)
        translateX = translateX * constant
        translateY = translateY * constant

        switch gesture.state {
        case .began:
            previousTranslation = node!.position
            break;
        case .changed:
            node!.position = SCNVector3Make((previousTranslation.x + translateX), previousTranslation.y, (previousTranslation.z + translateY))
            break
        default: break
        }
    }
}

度:

@objc func rotate(gesture: UIPanGestureRecognizer) {
    gesture.minimumNumberOfTouches = 2
    gesture.maximumNumberOfTouches = 2
    if gesture.numberOfTouches == 2 {
        let view = self.view as! SCNView
        let node = view.scene!.rootNode.childNode(withName: "CameraHandler", recursively: false)
        let translate = gesture.translation(in: view)

        var widthRatio:Float = 0

        widthRatio = Float(translate.x / 10) * Float(Double.pi / 180)

        switch gesture.state {
        case .began:
            lastWidthRatio = node!.eulerAngles.y
            break
        case .changed:
            node!.eulerAngles.y = lastWidthRatio + widthRatio
            print(node!.eulerAngles.y)
            break
        default: break
        }
    }
}

CameraHandler节点是Camera节点的父节点。一切正常,它只是像我想要的那样工作。希望这很清楚,让你们明白。

2 个答案:

答案 0 :(得分:1)

在目标C中。关键部分是最后三行,特别是最后一行中矩阵的乘法顺序(导致运动发生在局部空间中)。如果transmat和cammat被切换,它将像你现在一样再次行动(在世界空间中移动)。重构部分只适用于我可以使用透视和正交相机的特定情况。

-(void)panCamera :(CGPoint)location {

CGFloat dx = _prevlocation.x - location.x;
CGFloat dy = location.y - _prevlocation.y;
_prevlocation = location;

//refactor dx and dy based on camera distance or orthoscale
if (cameraNode.camera.usesOrthographicProjection) {
    dx = dx / 416 * cameraNode.camera.orthographicScale;
    dy = dy / 416 * cameraNode.camera.orthographicScale;
} else {
    dx = dx / 720 * cameraNode.position.z;
    dy = dy / 720 * cameraNode.position.z;
}

SCNMatrix4 cammat = self.cameraNode.transform;
SCNMatrix4 transmat = SCNMatrix4MakeTranslation(dx, 0, dy);
self.cameraNode.transform = SCNMatrix4Mult(transmat, cammat);

}

答案 1 :(得分:0)

根据Xartec的回答,我想出来了。我把它翻译成了一个快速和复古的装置,以便与我需要的东西一起工作。我对此并不满意,因为运动不顺畅。我今天晚些时候会努力平滑它。

平移手势:此手势按照相机旋转的方向平移场景周围的相机父节点。它完全像我想要的那样工作。

@objc func pan(gesture: UIPanGestureRecognizer) {
    gesture.minimumNumberOfTouches = 1
    gesture.maximumNumberOfTouches = 1
    if gesture.numberOfTouches == 1 {
        let view = self.view as! SCNView
        let node = view.scene!.rootNode.childNode(withName: "CameraHandler", recursively: false)
        let translation = gesture.translation(in: view)

        var dx = previousTranslation.x - translation.x
        var dy = previousTranslation.y - translation.y

        dx = dx / 100
        dy = dy / 100
        print(dx,dy)

        let cammat = node!.transform
        let transmat = SCNMatrix4MakeTranslation(Float(dx), 0, Float(dy))

        switch gesture.state {
        case .began:
            previousTranslation = translation
            break;
        case .changed:
            node!.transform = SCNMatrix4Mult(transmat, cammat)
            break
        default: break
        }
    }
}

旋转手势:此手势用两根手指旋转相机。

@objc func rotate(gesture: UIPanGestureRecognizer) {
    gesture.minimumNumberOfTouches = 2
    gesture.maximumNumberOfTouches = 2
    if gesture.numberOfTouches == 2 {
        let view = self.view as! SCNView
        let node = view.scene!.rootNode.childNode(withName: "CameraHandler", recursively: false)
        let translate = gesture.translation(in: view)

        var widthRatio:Float = 0
        widthRatio = Float(translate.x / 10) * Float(Double.pi / 180)

        switch gesture.state {
        case .began:
            lastWidthRatio = node!.eulerAngles.y
            break
        case .changed:
            node!.eulerAngles.y = lastWidthRatio + widthRatio
            break
        default: break
        }
    }
}

要获得与我相同的功能,您需要将cameraNode附加到父节点。像这样:

    //create and add a camera to the scene
    let cameraNode = SCNNode()

    //cameraHandler is declared outside viewDidLoad. 
    let cameraHandler = SCNNode()

    cameraNode.camera = SCNCamera()
    cameraNode.name = "Camera"
    cameraNode.position = SCNVector3(x: 0.0,y: 10.0,z: 20.0)
    //This euler angle only rotates the camera downward a little bit. It is not neccessary 
    cameraNode.eulerAngles = SCNVector3(x: -0.6, y: 0, z: 0)

    cameraHandler.addChildNode(cameraNode)
    cameraHandler.name = "CameraHandler"

    scene.rootNode.addChildNode(cameraHandler)