3D 向量的旋转和方向 space - 逆序
Rotation and direction of a vector in 3D space - Inverse Order
我有两个 3D 向量 - space、S
(开始)和 T
(目标),我想找到允许这样的旋转矩阵 (RM)转型。
我知道通过计算 叉积 S × T
我得到了旋转轴。 S
和 T
之间的角度由 tan⁻¹(||S × T||, S·T)
给出,其中 S·T
是 S 和 T 之间的 点积 。
这给了我旋转向量 rotvec = [S x T; angle]
(叉积已归一化)。然后通过使用函数 vrrotvec2mat (in MATLAB) or transforms3d.axangles.axangle2mat (在 Python 中)我可以获得对应于从 S
到 T
.
的转换的旋转矩阵
在我的应用程序中 T
由 点积 RM·D
给出,其中 D
是一个 3x1
向量. 我的目标是找到RM。我知道 S
、T
和 D
,但我很难理解这背后的数学原理。
实际上我想在 S
和 T'
之间找到一个 RM,其中 T'
是应用 D
(方向)之前的目标向量。
更多上下文:我想从相机坐标系中的 3D 点获取 body 关节角度。
为了完成这项工作,您还需要旋转中心(旋转后保持不变的点)...现在我们需要两个变换矩阵,一个表示变换前的坐标系,一个表示变换后的坐标系。
要构建 3D 变换矩阵,您需要 3 个垂直的基向量和原点位置,请参阅:
现在旋转轴将是基础向量之一,我们可以使用 S,T
作为第二个,所以第三个我们可以用叉积计算,原点将是旋转中心:
X = cross(S,T); // rotation axis
X /= |X|; // unit vector
Y = S; // start vector
Y /= |Y|; // unit vector
Z = cross(X,Y); // Z perpendicular to X,Y
Z /= |Z|; // unit vector
O = center_of_rotation;
因此从中构建 4x4 变换矩阵 A
。对 B
执行相同操作,但使用 T
而不是 S
。现在我们要计算差异变换,所以如果 p=(x,y,z,1)
是要变换的任何点,则:
p' = Inverse(A)*p
p' = B*p'
所以你的变换矩阵M
是:
M = Inverse(A)*B;
请注意,如果您使用不同的约定(乘法顺序、矩阵方向等),这将适用于标准 OpenGL 约定,方程式可能会改变。
您还可以使用 更有效、更准确地计算 Inverse(A)
。
如您所见,您不需要任何测角学或角度来执行此操作(矢量数学在这方面很好)
[Edit1] C++ 示例
它使用 VCL(你可以忽略的 AnsiString 和 mm_log)和我的矢量数学(使用的函数在第一个 link 中)。
//---------------------------------------------------------------------------
AnsiString matrix_prn(double *a)
{
int i; AnsiString s;
for (s ="(",i=0;i<16;i+=4) { if (a[i]>=0.0) s+=" "; s+=AnsiString().sprintf("%2.3lf,",a[i]); } s[s.Length()]=')'; s+="\r\n";
for (s+="(",i=1;i<16;i+=4) { if (a[i]>=0.0) s+=" "; s+=AnsiString().sprintf("%2.3lf,",a[i]); } s[s.Length()]=')'; s+="\r\n";
for (s+="(",i=2;i<16;i+=4) { if (a[i]>=0.0) s+=" "; s+=AnsiString().sprintf("%2.3lf,",a[i]); } s[s.Length()]=')'; s+="\r\n";
for (s+="(",i=3;i<16;i+=4) { if (a[i]>=0.0) s+=" "; s+=AnsiString().sprintf("%2.3lf,",a[i]); } s[s.Length()]=')';
return s;
}
//---------------------------------------------------------------------------
AnsiString vector_prn(double *a)
{
int i; AnsiString s;
for (s ="(",i=0;i<3;i++) { if (a[i]>=0.0) s+=" "; s+=AnsiString().sprintf("%2.3lf,",a[i]); } s[s.Length()]=')';
return s;
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
{
int i;
double O[3]={0.00, 0.00,0.00}; // center ofrotation
double S[3]={4.10,-9.44,0.54}; // start vector
double T[3]={1.40,-9.08,4.10}; // end vector
double A[16],_A[16],B[16],M[16],X[3],Y[3],Z[3];
// A
vector_mul(X,S,T); // rotation axis
vector_one(X,X); // unit vector
vector_one(Y,S); // unit start vector
vector_mul(Z,X,Y); // Z perpendicular to X,Y
vector_one(Z,Z); // unit vector
for (i=0;i<3;i++)
{
A[ 0+i]=X[i];
A[ 4+i]=Y[i];
A[ 8+i]=Z[i];
A[12+i]=O[i];
A[(i<<2)+3]=0.0;
} A[15]=1.0;
// B
vector_one(Y,T); // unit end vector
vector_mul(Z,X,Y); // Z perpendicular to X,Y
vector_one(Z,Z); // unit vector
for (i=0;i<3;i++)
{
B[ 0+i]=X[i];
B[ 4+i]=Y[i];
B[ 8+i]=Z[i];
B[12+i]=O[i];
B[(i<<2)+3]=0.0;
} B[15]=1.0;
// M = B*Inverse(A)
matrix_inv(_A,A);
matrix_mul(M,_A,B);
mm_log->Lines->Add("A");
mm_log->Lines->Add(matrix_prn(A));
mm_log->Lines->Add("B");
mm_log->Lines->Add(matrix_prn(B));
mm_log->Lines->Add("M");
mm_log->Lines->Add(matrix_prn(M));
mm_log->Lines->Add("");
vector_one(S,S); // unit start vector
vector_one(T,T); // unit end vector
mm_log->Lines->Add("S = "+vector_prn(S));
matrix_mul_vector(X,M,S);
mm_log->Lines->Add("X = "+vector_prn(X));
mm_log->Lines->Add("T = "+vector_prn(T));
}
//-------------------------------------------------------------------------
结果如下:
A
(-0.760, 0.398,-0.514, 0.000)
(-0.361,-0.916,-0.175, 0.000)
(-0.540, 0.052, 0.840, 0.000)
( 0.000, 0.000, 0.000, 1.000)
B
(-0.760, 0.139,-0.635, 0.000)
(-0.361,-0.903, 0.235, 0.000)
(-0.540, 0.408, 0.736, 0.000)
( 0.000, 0.000, 0.000, 1.000)
M
( 0.959, 0.258,-0.115, 0.000)
(-0.205, 0.916, 0.345, 0.000)
( 0.194,-0.307, 0.932, 0.000)
( 0.000, 0.000, 0.000, 1.000)
S = ( 0.398,-0.916, 0.052)
X = ( 0.139,-0.903, 0.408) // X = M * S
T = ( 0.139,-0.903, 0.408)
如您所见,如果我将单位 S
转换为 M
,我得到了单位 T
向量。 PS。我的 matrix_mul_vector
和 vector_mul
假设 w=1.0
但因为 O=(0.0,0.0,0.0)
向量和点是相同的。
我有两个 3D 向量 - space、S
(开始)和 T
(目标),我想找到允许这样的旋转矩阵 (RM)转型。
我知道通过计算 叉积 S × T
我得到了旋转轴。 S
和 T
之间的角度由 tan⁻¹(||S × T||, S·T)
给出,其中 S·T
是 S 和 T 之间的 点积 。
这给了我旋转向量 rotvec = [S x T; angle]
(叉积已归一化)。然后通过使用函数 vrrotvec2mat (in MATLAB) or transforms3d.axangles.axangle2mat (在 Python 中)我可以获得对应于从 S
到 T
.
在我的应用程序中 T
由 点积 RM·D
给出,其中 D
是一个 3x1
向量. 我的目标是找到RM。我知道 S
、T
和 D
,但我很难理解这背后的数学原理。
实际上我想在 S
和 T'
之间找到一个 RM,其中 T'
是应用 D
(方向)之前的目标向量。
更多上下文:我想从相机坐标系中的 3D 点获取 body 关节角度。
为了完成这项工作,您还需要旋转中心(旋转后保持不变的点)...现在我们需要两个变换矩阵,一个表示变换前的坐标系,一个表示变换后的坐标系。
要构建 3D 变换矩阵,您需要 3 个垂直的基向量和原点位置,请参阅:
现在旋转轴将是基础向量之一,我们可以使用 S,T
作为第二个,所以第三个我们可以用叉积计算,原点将是旋转中心:
X = cross(S,T); // rotation axis
X /= |X|; // unit vector
Y = S; // start vector
Y /= |Y|; // unit vector
Z = cross(X,Y); // Z perpendicular to X,Y
Z /= |Z|; // unit vector
O = center_of_rotation;
因此从中构建 4x4 变换矩阵 A
。对 B
执行相同操作,但使用 T
而不是 S
。现在我们要计算差异变换,所以如果 p=(x,y,z,1)
是要变换的任何点,则:
p' = Inverse(A)*p
p' = B*p'
所以你的变换矩阵M
是:
M = Inverse(A)*B;
请注意,如果您使用不同的约定(乘法顺序、矩阵方向等),这将适用于标准 OpenGL 约定,方程式可能会改变。
您还可以使用 Inverse(A)
。
如您所见,您不需要任何测角学或角度来执行此操作(矢量数学在这方面很好)
[Edit1] C++ 示例
它使用 VCL(你可以忽略的 AnsiString 和 mm_log)和我的矢量数学(使用的函数在第一个 link 中)。
//---------------------------------------------------------------------------
AnsiString matrix_prn(double *a)
{
int i; AnsiString s;
for (s ="(",i=0;i<16;i+=4) { if (a[i]>=0.0) s+=" "; s+=AnsiString().sprintf("%2.3lf,",a[i]); } s[s.Length()]=')'; s+="\r\n";
for (s+="(",i=1;i<16;i+=4) { if (a[i]>=0.0) s+=" "; s+=AnsiString().sprintf("%2.3lf,",a[i]); } s[s.Length()]=')'; s+="\r\n";
for (s+="(",i=2;i<16;i+=4) { if (a[i]>=0.0) s+=" "; s+=AnsiString().sprintf("%2.3lf,",a[i]); } s[s.Length()]=')'; s+="\r\n";
for (s+="(",i=3;i<16;i+=4) { if (a[i]>=0.0) s+=" "; s+=AnsiString().sprintf("%2.3lf,",a[i]); } s[s.Length()]=')';
return s;
}
//---------------------------------------------------------------------------
AnsiString vector_prn(double *a)
{
int i; AnsiString s;
for (s ="(",i=0;i<3;i++) { if (a[i]>=0.0) s+=" "; s+=AnsiString().sprintf("%2.3lf,",a[i]); } s[s.Length()]=')';
return s;
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
{
int i;
double O[3]={0.00, 0.00,0.00}; // center ofrotation
double S[3]={4.10,-9.44,0.54}; // start vector
double T[3]={1.40,-9.08,4.10}; // end vector
double A[16],_A[16],B[16],M[16],X[3],Y[3],Z[3];
// A
vector_mul(X,S,T); // rotation axis
vector_one(X,X); // unit vector
vector_one(Y,S); // unit start vector
vector_mul(Z,X,Y); // Z perpendicular to X,Y
vector_one(Z,Z); // unit vector
for (i=0;i<3;i++)
{
A[ 0+i]=X[i];
A[ 4+i]=Y[i];
A[ 8+i]=Z[i];
A[12+i]=O[i];
A[(i<<2)+3]=0.0;
} A[15]=1.0;
// B
vector_one(Y,T); // unit end vector
vector_mul(Z,X,Y); // Z perpendicular to X,Y
vector_one(Z,Z); // unit vector
for (i=0;i<3;i++)
{
B[ 0+i]=X[i];
B[ 4+i]=Y[i];
B[ 8+i]=Z[i];
B[12+i]=O[i];
B[(i<<2)+3]=0.0;
} B[15]=1.0;
// M = B*Inverse(A)
matrix_inv(_A,A);
matrix_mul(M,_A,B);
mm_log->Lines->Add("A");
mm_log->Lines->Add(matrix_prn(A));
mm_log->Lines->Add("B");
mm_log->Lines->Add(matrix_prn(B));
mm_log->Lines->Add("M");
mm_log->Lines->Add(matrix_prn(M));
mm_log->Lines->Add("");
vector_one(S,S); // unit start vector
vector_one(T,T); // unit end vector
mm_log->Lines->Add("S = "+vector_prn(S));
matrix_mul_vector(X,M,S);
mm_log->Lines->Add("X = "+vector_prn(X));
mm_log->Lines->Add("T = "+vector_prn(T));
}
//-------------------------------------------------------------------------
结果如下:
A
(-0.760, 0.398,-0.514, 0.000)
(-0.361,-0.916,-0.175, 0.000)
(-0.540, 0.052, 0.840, 0.000)
( 0.000, 0.000, 0.000, 1.000)
B
(-0.760, 0.139,-0.635, 0.000)
(-0.361,-0.903, 0.235, 0.000)
(-0.540, 0.408, 0.736, 0.000)
( 0.000, 0.000, 0.000, 1.000)
M
( 0.959, 0.258,-0.115, 0.000)
(-0.205, 0.916, 0.345, 0.000)
( 0.194,-0.307, 0.932, 0.000)
( 0.000, 0.000, 0.000, 1.000)
S = ( 0.398,-0.916, 0.052)
X = ( 0.139,-0.903, 0.408) // X = M * S
T = ( 0.139,-0.903, 0.408)
如您所见,如果我将单位 S
转换为 M
,我得到了单位 T
向量。 PS。我的 matrix_mul_vector
和 vector_mul
假设 w=1.0
但因为 O=(0.0,0.0,0.0)
向量和点是相同的。