I'm writing a simple 3D engine myself and I cannot figure out how to make one object face another. The problem begins with identifying which direction the target object is in relation to the second. Actually rotating an object is not a problem, but essentially identifying the direction a particular object is facing (let's say, by identifying the global direction a key facet is facing) is a problem.
-
\$\begingroup\$ Are you using any particular engine? \$\endgroup\$– Steve SmithCommented Aug 2, 2016 at 8:31
-
\$\begingroup\$ I'm writing my own. Literally everything in it. So I have no support from outside libraries etc. \$\endgroup\$– Matt WCommented Aug 2, 2016 at 8:37
1 Answer
There are a couple ways to do this, but here's one way to do it. We can generate a rotation matrix by storing 3 normalized vectors as columns for a 3x3 matrix. The first column will be normalized vector pointing down our "X" axis, the second will be normalized vector pointing down our "Y" axis, and the final one will a normalized vector pointing down the "Z" axis. One example of this is an identity matrix, which is all 0's, except for the diagonal going from top right to bottom left. The first column is [1,0,0], which is a normalized vector pointing down the X axis, the second column points "up", and the third column points forward.
The first step is to get the vector from object 1 to object2, and normalize it. You now have a "forward vector". This will be our first column of the matrix.
Now we need a second column, which is our "up vector". Usually, we won't be rotated directly upwards (and if we are, I'll show you how to deal with it at the end), so we're going to guess at that axis. We'll set it to straight up, which is [0,1,0]. So now we have a 3x3 matrix with the first 2 columns set, it looks like this:
[ f.x 0 ? ]
[ f.y 1 ? ]
[ f.z 0 ? ]
We need the final column, our "tangent" vector. We can generate it by taking the cross product of the "forward" vector and the up vector, so now we have our forward vector, [f.x, f.y, f.z], an up vector [0, 1, 0], and a "tangent" vector, which is [t.x, t.y, t.z]. Remember how I mentioned earlier that our math won't work if our forward vector is pointed in the same direction as the up vector we guessed at? We're going to check for it. You have to check the length of the tangent vector, and if the length is close to 0, then we need to fix it up. Instead of taking the cross product of [f.x,f.y,f.z] and [0, 1, 0], we can pick a new axis for our 2nd vector, say [1, 0, 0]. Do the cross product again, and that vector is our tangent vector. Important step: normalize it. Once you've normalized it, it becomes our 3rd column.
So now we have a matrix with a forward vector in 1 column, a value we hard-coded in the second column, and a tangent vector in the 3rd column. We need to fix up that "up" vector we hard-coded earlier, so we need to take the cross product of the tangent vector and the forward vector, normalize it, and set the "up" column to that vector.
This final matrix is the rotation matrix to rotate object 1 to point at object 2. If you need to, you can convert this matrix to a quaternion, or euler angles, or some other if you need to store it. Here's some pseudo code on this process, just for clarity:
Vector3 forward = object2.pos - object1.pos;
forward.normalize();
Vector3 up = new Vector3(0, 1.0, 0);
Vector3 tangent0 = CrossProduct(forward, up);
if (tangent0.length < 0.001f)
{
up = new Vector3(1.0, 0, 0);
tangent0 = CrossProduct(forward, up);
}
tangent0.normalize();
up = CrossProduct(forward, tangent0);
Matrix rotation = new Matrix(
forward.x, up.x, tangent0.x,
forward.y, up.y, tangent0.y,
forward.z, up.z, tangent0.z
);