这个问题可以通过旋转矩阵或四元数来解决,但是我建议使用旋转矩阵路线,因为您可以通过单个矩阵乘法同时解决所有点。
旋转矩阵:如果您知道要旋转的欧拉角,那么旋转矩阵就是要走的路。要形成旋转矩阵,请参阅链接的“基本旋转”部分。而不是知道什么是“向上”,您需要知道您希望旋转对象的程度。在这种情况下(从提供的照片来看),您想围绕全局x 轴旋转 90 度(如果您想围绕局部轴旋转,您必须知道对象的当前方向。我可以在编辑中详细说明如果您需要局部旋转)。您的全局旋转矩阵将是:
[1 0 0]
[0 0 1]
[0 -1 0]
我是通过使用“基本旋转”部分中的 Rx(90) 矩阵计算得出的。现在,在列向量中形成 3D 点。假设一个点位于 (0,0,1)。这个点直接就是鼻子所在的位置,所以我们希望转换后的点是 (0,1,0)。只需左乘旋转矩阵即可得到结果:
[1 0 0] [0] [0]
[0 0 1]*[0]=[1]
[0 -1 0] [1] [0]
请注意,在这种情况下,转换是相当微不足道的;我们只是简单地移动坐标(x 保持不变,y 取反,z 和 y 交换)。您可以通过水平连接所有初始坐标以形成 3xN 矩阵,然后左乘旋转矩阵来同时变换大量点。例如,让我们变换点 { (0,0,1), (0,1,0), (1,0,1), (0,0,-1) }:
[1 0 0] [0 0 1 0] [0 0 1 0]
[0 0 1]*[0 1 0 0]=[1 0 1 0]
[0 -1 0] [1 0 1 -1] [0 -1 0 1]
提醒一下,这个变换围绕全局原点旋转(如 (1,0,1) 点所示)。您必须减去坐标的质心,旋转,然后添加最终的平移坐标。
四元数:我可以在这里给出一个教程,但这通常被称为“轴角”符号;您可以使用它来创建一个旋转矩阵,该矩阵将围绕任意单位轴将您的点旋转指定角度。 这是一个很棒的教程。让我知道我是否应该在编辑中详细说明。
编辑:响应添加的伪代码
如果叉积为 0,则线平行。旋转轴可以是垂直于任一输入的任何矢量(根据定义使其垂直于两者)。如果dot(v,p)==0,或者vx*p.x+vy*p.y+vz*pz==0且length(p)>0,则向量p被定义为垂直,所以我们可以任意选择任何满足这些方程的解。
v1 = vector(0,10,0)
v2 = vector(0,-10,0)
//Not necessary, since you will normalize the cross product result
//v1 = normalize(v1)
//v2 = normalize(v2)
cross = v2.cross(v1) // (0,0,0) and possible divide by 0 if normalized here
if(length(cross)==0){ //either "==0" or "<thresh" where thresh is some very small number
if(v.z!=0)
cross = vector(1,1,-(v1.x+v1.y)/v1.z);
else if(v.y!=0) //is z==0? well here's an identical solution as long as y isn't 0
cross = vector(1,-(v1.x+v1.z)/v.y,1);
else //by this point, v1.x must be the only nonzero remaining point, otherwise it's a null vector
cross = vector(-(v1.y+v1.z)/v.x,1,1);
}
cross=normalize(cross);
angle = acos( normalize(v2.dot(v1)) ) // 180
quat = quaternion(cross,angle)
我不熟悉 python 代码,所以我添加了 C++ 等价物。如果有人可以编辑这篇文章来纠正它,那就太好了。
编辑:我没有看到您对 acos 的评论,对此感到抱歉。相应地更改了代码。