0

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

面对原始位置 在所需位置面对

我可以用 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}

4

1 回答 1

3

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

旋转矩阵:如果您知道要旋转的欧拉角,那么旋转矩阵就是要走的路。要形成旋转矩阵,请参阅链接的“基本旋转”部分。而不是知道什么是“向上”,您需要知道您希望旋转对象的程度。在这种情况下(从提供的照片来看),您想围绕全局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 的评论,对此感到抱歉。相应地更改了代码。

于 2013-04-27T09:09:57.597 回答