首页 文章

如何使用 4x4 矩阵变换或欧拉角度旋转 3d 矢量?

提问于
浏览
4

我有一个 3d 矢量我正在申请作为一个物理力量:

let force = SCNVector3(x: 0, y: 0, z: -5)  
node.physicsBody?.applyForce(force, asImpulse: true)

我需要根据移动设备的位置旋转力,这可以作为 4x4 矩阵变换或欧拉角。

var transform :matrix_float4x4 - 摄像机在世界坐标空间中的位置和方向。

var eulerAngles :vector_float3 - 摄像机的方向,表示为滚动,俯仰和偏航值。

我认为这更像是一个基本的 3D 图形问题,但这个应用程序是使用 SceneKit 和 ARKit 的基于 Swift 的 iOS 应用程序。

SceneKit和 simd 库中有一些可用的实用程序。不幸的是,我天真地尝试做像simd_mul(force, currentFrame.camera.transform)这样的事情让我失望了。

2 回答

  • 6

    @orangenkopf provided a 很好的答案帮助我想出了这个:

    let force = simd_make_float4(0, 0, -5, 0)
    let rotatedForce = simd_mul(currentFrame.camera.transform, force)
    let vectorForce = SCNVector3(x:rotatedForce.x, y:rotatedForce.y, z:rotatedForce.z)
    node.physicsBody?.applyForce(vectorForce, asImpulse: true)
    
  • 3

    你的想法是对的。您需要将变换和方向相乘。我在simd_mul上找不到任何文档。但我怀疑你至少有以下一个问题:

    • simd_mul同时应用变换的旋转和平移

    • 摄像机的变换位于世界坐标空间中。根据您的节点层次结构,这可能会导致方向偏离。

    SceneKit 没有提供太多的线性代数函数,所以我们必须自己构建:

    extension SCNMatrix4 {
        static public func *(left: SCNMatrix4, right: SCNVector4) -> SCNVector4 {
            let x = left.m11*right.x + left.m21*right.y + left.m31*right.z + left.m41*right.w
            let y = left.m12*right.x + left.m22*right.y + left.m32*right.z + left.m42*right.w
            let z = left.m13*right.x + left.m23*right.y + left.m33*right.z + left.m43*right.w
            let w = left.m14*right.x + left.m24*right.y + left.m43*right.z + left.m44*right.w
    
            return SCNVector4(x: x, y: y, z: z, w: w)
        }
    }
    extension SCNVector4 {
        public func to3() -> SCNVector3 {
            return SCNVector3(self.x , self.y, self.z)
        }
    }
    

    现在执行以下操作:

    • 将摄像机变换转换为节点局部坐标系

    • 将力创建为 4d 向量,将第四个元素设置为 0 以忽略转换

    • 将变换和矢量相乘


    // Convert the tranform to a SCNMatrix4
    let transform = SCNMatrix4FromMat4(currentFrame.camera.transform)
    // Convert the matrix to the nodes coordinate space
    let localTransform = node.convertTransform(transform, from: nil)
    
    let force = SCNVector4(0, 0, -5, 0)
    let rotatedForce = (localTransform * force).to3()
    
    node.physicsBody?.applyForce(rotatedForce, asImpulse: true)
    

相关问题