围绕一个轴的四元数旋转的分量
我无法find有关此主题的任何良好信息。 基本上我想find一个四元数旋转的分量,即围绕一个给定的轴(不一定是X,Y或Z–任何任意单位向量)。 有点像将四元数映射到vector上。 所以如果我要求绕与四元数轴平行的轴旋转,我会得到相同的四元数。 如果我要求围绕与四元数轴正交的轴旋转,我会得到一个身份四元数。 而在…之间……好吧,这就是我想知道如何解决的:)
有一天,我花了一段时间去为animation编辑器find完全相同的东西。 这是我是如何做到的:
- 以你想要find的旋转轴为中心,find一个正交向量。
- 使用你的四元数旋转这个新的向量。
- 将这个旋转的vector投影到以法线为轴的平面上
-
这个投影向量和原始正交的点积的angular是你的angular度。
public static float FindQuaternionTwist(Quaternion q, Vector3 axis) { axis.Normalize();
//get the plane the axis is a normal of Vector3 orthonormal1, orthonormal2; ExMath.FindOrthonormals(axis, out orthonormal1, out orthonormal2); Vector3 transformed = Vector3.Transform(orthonormal1, q); //project transformed vector onto plane Vector3 flattened = transformed - (Vector3.Dot(transformed, axis) * axis); flattened.Normalize(); //get angle between original vector and projected transform to get angle around normal float a = (float)Math.Acos((double)Vector3.Dot(orthonormal1, flattened)); return a;
}
这里是find标准正则expression式的代码,但是如果你只想要上面的方法,你可能会做得更好:
private static Matrix OrthoX = Matrix.CreateRotationX(MathHelper.ToRadians(90)); private static Matrix OrthoY = Matrix.CreateRotationY(MathHelper.ToRadians(90)); public static void FindOrthonormals(Vector3 normal, out Vector3 orthonormal1, out Vector3 orthonormal2) { Vector3 w = Vector3.Transform(normal,OrthoX); float dot = Vector3.Dot(normal, w); if (Math.Abs(dot) > 0.6) { w = Vector3.Transform(normal,OrthoY); } w.Normalize(); orthonormal1 = Vector3.Cross(normal, w); orthonormal1.Normalize(); orthonormal2 = Vector3.Cross(normal, orthonormal1); orthonormal2.Normalize(); }
虽然上面的作品,你可能会发现它不像你所期望的那样。 例如,如果你的四元数旋转一个向量90度。 在X和90度附近。 在Y轴上你会发现如果你分解Z轴的旋转angular度是90度。 以及。 如果你想象一个vector做这些旋转,那么这是非常有道理的,但取决于你的应用程序,它可能不是理想的行为。 对于我的应用程序 – 约束骨骼关节 – 我结束了一个混合系统。 matrix/四舍五入,但是当涉及到限制关节的方法时,我在内部使用了欧拉angular,每次将旋转四舍五入分解为围绕X,Y,Z的旋转。
祝你好运,希望有所帮助。
这个问题有一个很好的解决scheme,特别适用于四元数。 它被称为“摆动扭曲分解”:
伪代码
/** Decompose the rotation on to 2 parts. 1. Twist - rotation around the "direction" vector 2. Swing - rotation around axis that is perpendicular to "direction" vector The rotation can be composed back by rotation = swing * twist has singularity in case of swing_rotation close to 180 degrees rotation. if the input quaternion is of non-unit length, the outputs are non-unit as well otherwise, outputs are both unit */ inline void swing_twist_decomposition( const xxquaternion& rotation, const vector3& direction, xxquaternion& swing, xxquaternion& twist) { vector3 ra( rotation.x, rotation.y, rotation.z ); // rotation axis vector3 p = projection( ra, direction ); // return projection v1 on to v2 (parallel component) twist.set( px, py, pz, rotation.w ); twist.normalize(); swing = rotation * twist.conjugated(); }
而这个代码的长答案和派生可以在这里findhttp://www.euclideanspace.com/maths/geometry/rotations/for/decomposition/
我试图实现sebf的答案,似乎很好,除了在步骤1中selectvector的select:
- 以你想要find的旋转轴为中心,find一个正交向量。
对于可重复的结果是不够的。 我已经在纸上开发了这一点,为了select与“想要find旋转的轴”(即观察轴)正交的向量,我build议采取以下行动。 有一个与观察轴正交的平面。 你必须把你的四元数的旋转轴投影到这个平面上。 使用这个结果向量作为与观察轴正交的向量将会给出好的结果。
感谢sebf让我放下正确的路线。