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

How do I rotate a 3d vector with a 4x4 matrix transform or euler angles?

我有一个 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 - The position and orientation of the camera in world coordinate space.

var eulerAngles :vector_float3 - The orientation of the camera, expressed as roll, pitch, and yaw values.

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

SceneKit 和 simd 库中有一些实用程序可供我使用。不幸的是,我天真的尝试做 simd_mul(force, currentFrame.camera.transform) 之类的事情让我失败了。

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

  1. simd_mul 应用变换的旋转和平移
  2. 摄像机的变换在世界坐标系中space。根据您的节点层次结构,这可能会导致偏离方向。

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. 将变换和向量相乘

// 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)

@orangenkopf 提供了一个 帮助我想出这个:

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)