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

时间:2017-06-25 15:01:43

标签: ios matrix graphics 3d scenekit

我有一个3d矢量我作为物理力量应用:

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

我需要根据mobile device's position将力旋转为4x4矩阵变换或欧拉角。

  

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

     

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

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

我可以在SceneKit和simd库中使用一些实用工具。不幸的是,我天真地试图做simd_mul(force, currentFrame.camera.transform)这样的事情让我失望。

2 个答案:

答案 0 :(得分:6)

@orangenkopf提供了great answer,帮助我提出了这个问题:

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)

答案 1 :(得分:3)

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

  1. simd_mul同时应用转换的旋转和转换
  2. 摄像机的变换位于世界坐标空间中。根据您的节点层次结构,这可能导致方向偏离。
  3. 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)
        }
    }
    

    现在执行以下操作:

    1. 将摄像机变换转换为节点局部坐标系
    2. 将力创建为4d向量,将第四个元素设置为0以忽略转换
    3. 将变换和向量相乘
    4. // 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)