Graphics 矩阵绕任意轴旋转

Graphics 矩阵绕任意轴旋转,graphics,3d,linear-algebra,Graphics,3d,Linear Algebra,我一直在尝试让矩阵绕任意轴旋转,我认为我很接近,但我有一个错误。我对3D旋转比较陌生,对正在发生的事情有一个基本的了解 public static Matrix4D Rotate(Vector3D u, Vector3D v) { double angle = Acos(u.Dot(v)); Vector3D axis = u.Cross(v); double c = Cos(angle); double s = Sin(angle); double t

我一直在尝试让矩阵绕任意轴旋转,我认为我很接近,但我有一个错误。我对3D旋转比较陌生,对正在发生的事情有一个基本的了解

public static Matrix4D Rotate(Vector3D u, Vector3D v)
{
    double angle = Acos(u.Dot(v));
    Vector3D axis = u.Cross(v);

    double c = Cos(angle);
    double s = Sin(angle);
    double t = 1 - c;

    return  new Matrix4D(new double [,]
    {
        { c + Pow(axis.X, 2) * t,  axis.X * axis.Y * t -axis.Z * s, axis.X * axis.Z * t + axis.Y * s, 0 },
        { axis.Y * axis.X * t + axis.Z * s, c + Pow(axis.Y, 2) * t, axis.Y * axis.Z * t - axis.X * s, 0 },
        { axis.Z * axis.X * t - axis.Y * s, axis.Z * axis.Y * t + axis.X * s, c + Pow(axis.Z, 2) * t, 0 },
        { 0, 0, 0, 1 }
    });
}
上面的代码是矩阵旋转的算法。当我用单位向量测试算法时,我得到以下结果:

Matrix4D rotationMatrix = Matrix4D.Rotate(new Vector3D(1, 0, 0), new Vector3D(0, 0, 1));

Vector4D vectorToRotate = new Vector4D(1,0,0,0);

Vector4D result = rotationMatrix * vectorToRotate;

//Result
X = 0.0000000000000000612;
Y = 0;
Z = 1;
Length = 1;
旋转90度,我发现它几乎可以完美地工作。现在让我们看看45度旋转:

Matrix4D rotationMatrix = Matrix4D.Rotate(new Vector3D(1, 0, 0), new Vector3D(1, 0, 1).Normalize());

Vector4D vectorToRotate = new Vector4D(1,0,0,0);

Vector4D result = rotationMatrix * vectorToRotate;

//Result
X = .70710678118654746;
Y = 0;
Z = .5;
Length = 0.8660254037844386;

当我们使用atan(.5/.707)时,我们发现我们有35.28度的旋转,而不是45度的旋转。向量的长度也从1变为.866。有人知道我做错了什么吗?

你的矩阵代码看起来是正确的,但是你也需要对轴进行规范化(仅仅因为
u
v
被规范化并不意味着
u交叉v
也被规范化)


(出于性能和准确性的考虑,我还建议使用简单的乘法而不是
Pow
;但这是次要的,不是问题的根源)

您的矩阵代码看起来是正确的,但您也需要规范化轴(仅仅因为
u
v
是标准化的,并不意味着
u交叉v
也是标准化的)


(出于性能和准确性的考虑,我还建议使用简单的乘法而不是
Pow
;但这是次要的,不是问题的根源)

仅针对子孙后代,这就是我用于这件事的代码。我总是建议使用
Atan2(dy,dx)
而不是
Acos(dx)
因为在接近90°的角度下,它在数值上更稳定

公共静态类循环
{
来自两个向量的公共静态矩阵x4x4(向量3 u,向量3 v)
{
向量3 n=向量3.交叉(u,v);
double sin=n.Length();//使用| u×v |=| u | | v | sin(θ)
double cos=Vector3.Dot(u,v);//使用u·v=|u | v | cos(θ)
//如果u×v=0,或u·v=0,该怎么办?下面的全象限弧tan可以。
双角度=Atan2(正、反方向);
n=矢量3.归一化(n);
从轴角度返回(n,角度);
}
AxisAngle的公共静态矩阵x4x4(矢量3 n,双角度)
{
//假设'n'是标准化的
双x=n.x,y=n.y,z=n.z;
双正弦=正弦(角度);
双VCO=1.0-Cos(角度);
返回新矩阵x4(
1.0-vcos*(y*y+z*z),vcos*x*y-sin*z,vcos*x*z+sin*y,0,
vcos*x*y+sin*z,1.0-vcos*(x*x+z*z),vcos*y*z-sin*x,0,
vcos*x*z-sin*y,vcos*y*z+sin*x,1.0-vcos*(x*x+y*y),0,
0, 0, 0, 1.0);
}
}

代码是C#

只是为了子孙后代,这就是我用来做这件事的代码。我总是建议使用Atan2(dy,dx)而不是Acos(dx),因为它在90°角附近的数值上更稳定

公共静态类循环
{
来自两个向量的公共静态矩阵x4x4(向量3 u,向量3 v)
{
向量3 n=向量3.交叉(u,v);
double sin=n.Length();//使用| u×v |=| u | | v | sin(θ)
double cos=Vector3.Dot(u,v);//使用u·v=|u | v | cos(θ)
//如果u×v=0,或u·v=0,该怎么办?下面的全象限弧tan可以。
双角度=Atan2(正、反方向);
n=矢量3.归一化(n);
从轴角度返回(n,角度);
}
AxisAngle的公共静态矩阵x4x4(矢量3 n,双角度)
{
//假设'n'是标准化的
双x=n.x,y=n.y,z=n.z;
双正弦=正弦(角度);
双VCO=1.0-Cos(角度);
返回新矩阵x4(
1.0-vcos*(y*y+z*z),vcos*x*y-sin*z,vcos*x*z+sin*y,0,
vcos*x*y+sin*z,1.0-vcos*(x*x+z*z),vcos*y*z-sin*x,0,
vcos*x*z-sin*y,vcos*y*z+sin*x,1.0-vcos*(x*x+y*y),0,
0, 0, 0, 1.0);
}
}

代码是C#

让我补充一点,使用Acos(u.Dot(v))获得角度不是很好,因为如果两个向量几乎垂直,结果是不稳定的。使用Atan2((u.Cross(v))。幅值,u.Dot(v))代替。让我补充一下,使用Acos(u.Dot(v))获得角度不是很好,因为如果两个向量几乎垂直,结果不稳定。请改用
Atan2((u.Cross(v)).幅值,u.Dot(v))