如何将脸部与世界空间中的位置对齐?

时间:2013-04-27 00:49:13

标签: python math 3d blender mesh

我有一个数学问题。假设我在某个世界位置有一个面(有3或4个顶点)。我想翻译/旋转网格,使面部“朝上”并居中(0,y,0)。什么是解决这个问题所需的公式?

Face at original position Face at desired position

我可以使用gui执行此操作(此示例只是appx -90度的x旋转),但我需要通过脚本执行此操作,因此我需要知道如何通过数学方式完成此操作。

编辑: 我还应该注意到,这些向量是我想要旋转的网格的一部分(原点在(0,0,0))直到v1在位置v2。

这是失败的伪代码:

v1 = vector(0,10,0)
v2 = vector(0,-10,0)

v1 = normalize(v1)
v2 = normalize(v2)

cross = normalize( v2.cross(v1) )  // (0,0,0)
angle = acos( v2.dot(v1) )  // 180

quat  = quaternion(cross,angle) // {w:1,x:0,y:0,z:0}

我原以为四元数会是这样的:{w:?,x:3.14159,y:0,z:0}或{w:?,x:0,y:0,z:3.14159} < / p>

1 个答案:

答案 0 :(得分:2)

这个问题可以通过旋转矩阵或四元数来解决,但我建议使用旋转矩阵路径,因为你可以用单个矩阵乘法同时求解所有点。

旋转矩阵:如果您知道要旋转的欧拉角度是什么,那么rotation matrix就可以了。要形成旋转矩阵,请参阅链接的“基本旋转”部分。你不需要知道“向上”是什么,而是需要知道你希望旋转对象的程度。在这种情况下(根据提供的照片判断),您想围绕全局 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)点所示)。您必须减去坐标的质心,旋转,然后添加最终的平移坐标。

Quaternion:我可以在这里给出一个教程,但这通常被称为“轴角”符号;您可以使用它来创建旋转矩阵,该旋转矩阵将围绕任意单位轴旋转指定角度的点。 Here是一个很棒的教程。如果我应该在编辑中详细说明,请告诉我。

编辑:响应添加的伪代码

如果叉积为0,则线条平行。旋转轴可以是垂直于EITHER输入的任意矢量(根据定义使其垂直于两者)。如果点(v,p)== 0,或者vx * p.x + vy * p.y + vz * pz == 0和长度(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的评论,抱歉。相应地更改了代码。