ios - 如何使用平移手势在 SceneKit 中使用四元数旋转相机

标签 ios swift scenekit quaternions

我正在使用 iOS 构建 360 度视频查看器 SceneKit框架。

我想使用 UIPanGestureRecognizer来控制相机的方向。

SCNNode s 有几个我们可以用来指定它们的旋转的属性:rotation(一个旋转矩阵),orientation(一个四元数),eulerAngles(每个轴角度)。

我读过的所有内容都说要避免使用欧拉角以避免 gimbal lock .

我想使用四元数有几个原因,我不会在这里详述。

我无法让它正常工作。相机控制几乎是我想要的地方,但有些地方不对劲。尽管我试图只影响 X 轴和 Y 轴,但看起来相机正在绕 Z 轴旋转。

我认为这个问题与我的四元数乘法逻辑有关。多年来我没有做过任何与四元数相关的事情:(我的平移手势处理程序在这里:

func didPan(recognizer: UIPanGestureRecognizer)
{
    switch recognizer.state
    {
    case .Began:
        self.previousPanTranslation = .zero

    case .Changed:
        guard let previous = self.previousPanTranslation else
        {
            assertionFailure("Attempt to unwrap previous pan translation failed.")

            return
        }

        // Calculate how much translation occurred between this step and the previous step
        let translation = recognizer.translationInView(recognizer.view)
        let translationDelta = CGPoint(x: translation.x - previous.x, y: translation.y - previous.y)

        // Use the pan translation along the x axis to adjust the camera's rotation about the y axis.
        let yScalar = Float(translationDelta.x / self.view.bounds.size.width)
        let yRadians = yScalar * self.dynamicType.MaxPanGestureRotation

        // Use the pan translation along the y axis to adjust the camera's rotation about the x axis.
        let xScalar = Float(translationDelta.y / self.view.bounds.size.height)
        let xRadians = xScalar * self.dynamicType.MaxPanGestureRotation

        // Use the radian values to construct quaternions
        let x = GLKQuaternionMakeWithAngleAndAxis(xRadians, 1, 0, 0)
        let y = GLKQuaternionMakeWithAngleAndAxis(yRadians, 0, 1, 0)
        let z = GLKQuaternionMakeWithAngleAndAxis(0, 0, 0, 1)
        let combination = GLKQuaternionMultiply(z, GLKQuaternionMultiply(y, x))

        // Multiply the quaternions to obtain an updated orientation
        let scnOrientation = self.cameraNode.orientation
        let glkOrientation = GLKQuaternionMake(scnOrientation.x, scnOrientation.y, scnOrientation.z, scnOrientation.w)
        let q = GLKQuaternionMultiply(combination, glkOrientation)

        // And finally set the current orientation to the updated orientation
        self.cameraNode.orientation = SCNQuaternion(x: q.x, y: q.y, z: q.z, w: q.w)
        self.previousPanTranslation = translation

    case .Ended, .Cancelled, .Failed:
        self.previousPanTranslation = nil

    case .Possible:
        break
    }
}

我的代码在这里是开源的:https://github.com/alfiehanssen/360Player/

特别检查 pan-gesture 分支: https://github.com/alfiehanssen/360Player/tree/pan-gesture

如果您拉下代码,我相信您必须在设备上而不是模拟器上运行它。

我在这里发布了一个演示错误的视频(请原谅视频文件的低分辨率): https://vimeo.com/174346191

在此先感谢您的帮助!

最佳答案

我能够使用四元数来完成这项工作。完整代码在这里:ThreeSixtyPlayer .示例在这里:

    let orientation = cameraNode.orientation

    // Use the pan translation along the x axis to adjust the camera's rotation about the y axis (side to side navigation).
    let yScalar = Float(translationDelta.x / translationBounds.size.width)
    let yRadians = yScalar * maxRotation

    // Use the pan translation along the y axis to adjust the camera's rotation about the x axis (up and down navigation).
    let xScalar = Float(translationDelta.y / translationBounds.size.height)
    let xRadians = xScalar * maxRotation

    // Represent the orientation as a GLKQuaternion
    var glQuaternion = GLKQuaternionMake(orientation.x, orientation.y, orientation.z, orientation.w)

    // Perform up and down rotations around *CAMERA* X axis (note the order of multiplication)
    let xMultiplier = GLKQuaternionMakeWithAngleAndAxis(xRadians, 1, 0, 0)
    glQuaternion = GLKQuaternionMultiply(glQuaternion, xMultiplier)

    // Perform side to side rotations around *WORLD* Y axis (note the order of multiplication, different from above)
    let yMultiplier = GLKQuaternionMakeWithAngleAndAxis(yRadians, 0, 1, 0)
    glQuaternion = GLKQuaternionMultiply(yMultiplier, glQuaternion)

    cameraNode.orientation = SCNQuaternion(x: glQuaternion.x, y: glQuaternion.y, z: glQuaternion.z, w: glQuaternion.w)

关于ios - 如何使用平移手势在 SceneKit 中使用四元数旋转相机,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38319565/

相关文章:

sql - Swift 4 SQLITE 查询输出因 where 子句而失败

ios - SceneKit – SCNCamera 自上而下 View

camera - 带场景套件相机的鱼眼广角 : Possible?

iphone - 在 scrollViewWillBeginDragging 中检测 UIScrollView 滚动的方向

快速获取服务器时间

SwiftUI 列表 onTapGesture 覆盖了 NavigationLink

swift - ARKit – 如何显示来自放置在 SCNPlane 上的虚拟 SCNCamera 的提要?

ios - Swift - 如何为 FB Auth 处理来自 FIRUserInfo 的数据?

ios - 以编程方式从另一个应用程序打开一个应用程序

ios - 在 iOS 上使用 VoiceOver 时如何获取当前聚焦的元素?