如何使用 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
的任何文档。但我怀疑您至少有以下问题之一:
simd_mul
应用变换的旋转和平移
- 摄像机的变换在世界坐标系中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)
}
}
现在执行以下操作:
- 将相机变换转换为节点局部坐标系
- 将力创建为 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)
@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)
我有一个 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
的任何文档。但我怀疑您至少有以下问题之一:
simd_mul
应用变换的旋转和平移- 摄像机的变换在世界坐标系中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)
}
}
现在执行以下操作:
- 将相机变换转换为节点局部坐标系
- 将力创建为 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)
@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)