问题
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?


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.
EDIT: 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.
Here's the pseudo code that is failing:
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}
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}
回答1:
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.
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]
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]
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]
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.
EDIT: in response to the added pseudo code
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)
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.
Edit: I didn't see your comment about acos, sorry about that. Changed the code accordingly.
来源:https://stackoverflow.com/questions/16247177/how-to-align-a-face-to-a-position-in-world-space