问题描述
我有一道数学题.假设我在某个世界位置有一张脸(有 3 或 4 个顶点).我想平移/旋转网格,使面朝上"并居中 (0,y,0).实现这一目标需要什么公式?
I have a mathematical problem. Let's say I have a face (with 3 or 4 vertices) at some world position. I want to translate/rotate the mesh so that the face is "facing" up and is centered (0,y,0). What is the formula(s) needed to pull this off?
我可以使用 gui 执行此操作(此示例只是 appx -90 度的 x 旋转),但是我需要通过脚本执行此操作,因此我需要知道如何在数学上完成此操作.
I can do this with a gui (this example was simply an x rotation of appx -90 degrees), however I need to do this via a script so I need to know how this can be done mathematically.
我还应该注意,这些向量是我想要旋转的网格的一部分(起源于 (0,0,0))直到 v1 位于位置 v2.
I should also note that these vectors are part of a mesh which I'm wanting to rotate (origin at (0,0,0)) till v1 is at position 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}
I would have thought the quaternion would be something like: {w:?,x:3.14159,y:0,z:0} or {w:?,x:0,y:0,z:3.14159}
推荐答案
这个问题可以用旋转矩阵或四元数来解决,但是我建议使用旋转矩阵路线,因为你可以用一个单一的方法同时解决所有的点矩阵乘法.
This problem can be solved with either a rotation matrix or quaternions, however I would suggest the rotation matrix route because you can simultaneously solve all of the points with a single matrix multiplication.
旋转矩阵:如果您知道要旋转的欧拉角是多少,则使用 旋转矩阵 是要走的路.要形成旋转矩阵,请参阅链接的基本旋转"部分.与其知道向上"是什么,您还需要知道您希望将对象旋转多少.在这种情况下(从提供的照片来看),您想绕 global x 轴旋转 90 度(如果您想绕 local 轴旋转,则必须知道对象的当前方向.如果您需要局部旋转,我可以在编辑中详细说明).您的全局旋转矩阵将是:
Rotation Matrix: If you know what what euler angles you wish to rotate about, then a rotation matrix is the way to go. To form a rotation matrix, see the "Basic Rotations" section of the link. Rather than knowing what "up" is, you need to know how much you wish to rotate your object. In this case (judging from the photos provided), you want to rotate 90 degrees about the global x axis (if you wish to do it about a local axis, you must know the current orientation of the object. I can elaborate in an edit if you need local rotations). Your global rotation matrix will be:
[1 0 0]
[0 0 1]
[0 -1 0]
我使用基本旋转"部分中的 Rx(90) 矩阵计算了这一点.现在,在列向量中形成 3D 点.假设一个点在 (0,0,1) 处.该点直接位于鼻子所在的位置,因此我们预计变换点为 (0,1,0).只需左乘旋转矩阵即可获得结果:
I calculated this from using the Rx(90) matrix in the "Basic Rotations" section. Now, form your 3D points in column vectors. Let's say one point is at (0,0,1). This point is directly where the nose would be, so we expect the transformed point to be (0,1,0). Simply left multiply the rotation matrix to get your result:
[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) }:
Note that in this case the transformation is fairly trivial; we are simply shifting the coordinates around (x stays the same, y is negated, z and y are swapped). You can simultaneously transform a large set of points by horizontally concatenating all of the initial coordinates to form a 3xN matrix and then left multiplying the rotation matrix. For instance, let's transform the points { (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) 点所示).您必须减去坐标的质心,旋转,然后添加最终的平移坐标.
As a reminder, this transform rotates about the global origin (as illustrated by the (1,0,1) point). You will have to subtract the centroid of your coordinates, rotate, then add the final translation coordinates.
四元数:我可以在这里提供教程,但这通常称为轴角"表示法;您可以使用它来创建一个旋转矩阵,该矩阵将围绕任意单位轴旋转指定角度的点.这里是一个很好的教程.让我知道是否应该在编辑中详细说明.
Quaternion: I can give a tutorial here, but this is often referred to as "axis-angle" notation; you can use it to create a rotation matrix that will rotate your points about an arbitrary unit axis by a specified angle. Here is a great tutorial for that. Let me know if I should elaborate in an edit.
响应添加的伪代码
如果叉积为 0,则两条线平行.旋转轴可以是垂直于任一输入的任何向量(根据定义使其垂直于两者).如果 dot(v,p)==0 或 vx*p.x+vy*p.y+vz*pz==0 且 length(p)>0,则向量 p 被定义为垂直,因此我们可以任意选择任何满足这些方程的解.
If the cross product is 0, then the lines are parallel. The axis of rotation can be ANY vector perpendicular to EITHER input (which makes it perpendicular to both by definition). A vector p is defined as perpendicular if dot(v,p)==0, or v.x*p.x+v.y*p.y+v.z*p.z==0 and length(p)>0, so we can arbitrarily choose any solution that satisfies these equations.
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++ 等价物.如果有人可以编辑这篇文章来纠正它,那就太好了.
I'm not familiar with python code, so I added the C++ equivalent. If someone could edit this post to correct it, that'd be superb.
我没有看到你对 acos 的评论,抱歉.相应地更改了代码.
I didn't see your comment about acos, sorry about that. Changed the code accordingly.
这篇关于如何将人脸与世界空间中的位置对齐?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!