C# AxisAngleRotation3D到四元数会产生意外的结果

C# AxisAngleRotation3D到四元数会产生意外的结果,c#,wpf,3d,rotation,quaternions,C#,Wpf,3d,Rotation,Quaternions,我正在WPF 3D中开发一个控制器(使用C#),以便能够使用move()-和Pitch()-函数轻松移动和旋转ProjectionCamera。我的控制器将成为一个行为,可以附加到项目摄像机。为了初始化控制器,我想通过查看当前的Up和Forward-向量来计算相机的当前旋转,并将它们与默认相机方向进行比较(Up=[0 1 0],Forward=[0 0-1])。换句话说,我想计算一个旋转,将摄影机默认方向转换为当前方向 最终,我想将旋转表示为单个四元数,但作为中间步骤,我首先计算z-N-z形式的

我正在WPF 3D中开发一个控制器(使用C#),以便能够使用
move()
-和
Pitch()
-函数轻松移动和旋转
ProjectionCamera
。我的控制器将成为一个
行为
,可以附加到
项目摄像机
。为了初始化控制器,我想通过查看当前的
Up
Forward
-向量来计算相机的当前旋转,并将它们与默认相机方向进行比较(
Up=[0 1 0]
Forward=[0 0-1]
)。换句话说,我想计算一个旋转,将摄影机默认方向转换为当前方向

最终,我想将旋转表示为单个
四元数
,但作为中间步骤,我首先计算z-N-z形式的适当Euler角旋转,表示为
AxisAngleRotation3D
-值,默认定义如下:

根据一些单元测试,欧拉角旋转似乎计算正确。但是,当我将这些旋转转换为单个
四元数时,得到的
四元数
表示与Euler角旋转不同的旋转,我不知道为什么

以下是如何将Euler角度转换为单个四元数:

var rotation =
    new Quaternion(alphaRotation.Axis, alphaRotation.Angle) *
    new Quaternion(betaRotation.Axis, betaRotation.Angle) *
    new Quaternion(gammaRotation.Axis, gammaRotation.Angle);
例如,当我用
[1 0 0]
向上方向
初始化
投影摄像机时,这意味着它已绕其
[0 0-1]
轴旋转90度(
[0 0-1]
),计算的欧拉角旋转如下:

alphaRotation -->  90 deg. around [0 1 0]
betaRotation  -->  90 deg. around [0 0 -1]
gammaRotation --> -90 deg. around [1 0 0]
我的测试验证,当按顺序应用时,这些旋转将把默认的
Up
-矢量(
[0 1 0]
)转换为当前的
Up
-矢量(
[1 0 0]
),有效地绕
[0 0 0-1]
轴旋转90度。(手工验证也很简单。)

但是,当我将计算的
四元数旋转
应用于默认的
向上
-向量时,它被转换为向量
[-1 0]
,这显然是错误的。我在单元测试中硬编码了这些结果,得到了相同的结果:

    [TestMethod]
    public void ConversionTest()
    {
        var vector = new Vector3D(0, 1, 0);

        var alphaRotation = new AxisAngleRotation3D(new Vector3D(0, 1, 0), 90);
        var betaRotation = new AxisAngleRotation3D(new Vector3D(0, 0, -1), 90);
        var gammaRotation = new AxisAngleRotation3D(new Vector3D(1, 0, 0), -90);

        var a = new Quaternion(alphaRotation.Axis, alphaRotation.Angle);
        var b = new Quaternion(betaRotation.Axis, betaRotation.Angle);
        var c = new Quaternion(gammaRotation.Axis, gammaRotation.Angle);
        var combinedRotation = a * b * c;

        var x = Apply(vector, alphaRotation, betaRotation, gammaRotation);
        var y = Apply(vector, combinedRotation);
    }
当您运行上面的测试时,您将看到
x
为您提供了预期的向量(
[1 0]
),但是
y
将不同,它应该是完全相同的旋转


我遗漏了什么?

我解决了这个问题。显然,每个
四元数的乘法顺序应该颠倒。因此,要将Euler角度(或任何旋转集)转换为.NET中的单个
四元数
,应执行以下操作:

var rotation = gammaRotation * betaRotation * alphaRotation;

其中,
rotation
表示首先以几何方式应用
alphaRotation
,然后是
betaRotation
,最后是
gammaRotation
。我真希望他们能记录下来,因为订单的意义取决于您使用的特定库……

我解决了这个问题。显然,每个
四元数的乘法顺序应该颠倒。因此,要将Euler角度(或任何旋转集)转换为.NET中的单个
四元数
,应执行以下操作:

var rotation = gammaRotation * betaRotation * alphaRotation;

其中,
rotation
表示首先以几何方式应用
alphaRotation
,然后是
betaRotation
,最后是
gammaRotation
。我真希望他们能记录下来,因为顺序的含义取决于您使用的特定库……

@Sinatr:是的,我知道旋转的顺序。你发现我的密码有错误吗?因为据我所知,欧拉角必须按顺序(α,β,γ)应用,为了将旋转序列表示为一个四元数,你也必须按顺序(α*β*γ)乘以旋转量。@Sinatr:是的,我知道旋转的顺序很重要。你发现我的密码有错误吗?因为据我所知,欧拉角必须按顺序(alpha,beta,gamma)应用,并且要将旋转序列表示为一个四元数,还必须按此顺序(alpha*beta*gamma)乘以旋转。
var rotation = gammaRotation * betaRotation * alphaRotation;