我正在尝试将我的季铵化合物转换为欧拉,但在 x/y/z 分量中,只有我的 X 具有准确的值,而 y/z 不正确:- (任何人都可以查看/帮助吗?
func quatToEulerAngles(_ quat: simd_quatf) -> SIMD3<Double>{
var angles = SIMD3<Double>();
let qfloat = quat.vector
let q = SIMD4<Double>(Double(qfloat.x),Double(qfloat.y),Double(qfloat.z), Double(qfloat.w))
// roll (x-axis rotation)
let sinr_cosp : Double = 2.0 * (q.w * q.x + q.y * q.z);
let cosr_cosp : Double = 1.0 - 2.0 * (q.x * q.x + q.y * q.y);
angles.x = atan2(sinr_cosp, cosr_cosp);
// pitch (y-axis rotation)
let sinp : Double = 2 * (q.w * q.y - q.z * q.x);
if (abs(sinp) >= 1){
angles.y = copysign(Double.pi / 2, sinp); // use 90 degrees if out of range
}
else{
angles.y = asin(sinp);
}
// yaw (z-axis rotation)
let siny_cosp : Double = 2 * (q.w * q.z + q.x * q.y);
let cosy_cosp : Double = 1 - 2 * (q.y * q.y + q.z * q.z);
angles.z = atan2(siny_cosp, cosy_cosp);
return angles;
}
Wiki 示例已转换为 swifht。 TIA
我的解决方案是让(SceneKit)库来完成它:
func quatToEulerAngles(_ quat: simd_quatf) -> SIMD3<Float>{
let n = SCNNode()
n.simdOrientation = quat
return n.simdEulerAngles
}
我看了一下并将其转换为 Swift,
https://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/
它对我有用。
func quatToEulerAngles(_ quat: simd_quatf) -> SIMD3<Float>{
var angles = SIMD3<Float>();
let qfloat = quat.vector
// heading = x, attitude = y, bank = z
let test = qfloat.x*qfloat.y + qfloat.z*qfloat.w;
if (test > 0.499) { // singularity at north pole
angles.x = 2 * atan2(qfloat.x,qfloat.w)
angles.y = (.pi / 2)
angles.z = 0
return angles
}
if (test < -0.499) { // singularity at south pole
angles.x = -2 * atan2(qfloat.x,qfloat.w)
angles.y = -(.pi / 2)
angles.z = 0
return angles
}
let sqx = qfloat.x*qfloat.x;
let sqy = qfloat.y*qfloat.y;
let sqz = qfloat.z*qfloat.z;
angles.x = atan2(2*qfloat.y*qfloat.w-2*qfloat.x*qfloat.z , 1 - 2*sqy - 2*sqz)
angles.y = asin(2*test)
angles.z = atan2(2*qfloat.x*qfloat.w-2*qfloat.y*qfloat.z , 1 - 2*sqx - 2*sqz)
return angles
}
我只是想指出,依赖 SceneKit 进行转换可能会导致问题。我注意到,当从 Xcode 中的默认 SceneKit 项目绕 y(垂直)轴旋转船舶时,接近 90° 和 270° 的角度会导致生成的欧拉角绕 y 轴翻转 180°,从而导致错误的动画。以下代码演示了该问题。
import SceneKit
import QuartzCore
class GameViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
// create a new scene
let scene = SCNScene(named: "art.scnassets/ship.scn")!
// create and add a camera to the scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
// place the camera
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
// retrieve the ship node
let ship = scene.rootNode.childNode(withName: "ship", recursively: true)!
// animate the 3d object
let tempNode = SCNNode()
ship.runAction(.customAction(duration: 100, action: { node, t in
tempNode.simdOrientation = simd_quatf(angle: Float(t), axis: simd_float3(x: 0, y: 1, z: 0))
let eulerAngles = tempNode.eulerAngles
print(t, eulerAngles)
node.eulerAngles = eulerAngles
}))
// retrieve the SCNView
let scnView = self.view as! SCNView
// set the scene to the view
scnView.scene = scene
}
}