This should be easy, but I\'ve been all over trying to find a simple explanation that I can grasp. I have an object that I\'d like to represent in OpenGL as a cone. The ob
A helpful concept to remember here is that a linear transformation can also be interpreted as a change of coordinate systems. In other words, instead of picturing points being transformed within a coordinate system, you can just as well picture the points staying in place, but their coordinates being expressed in a new coordinate system. When looking at the matrix expressing the transformation, the base vectors of this new coordinate system are the column vectors of the matrix.
In the following, the base vectors of the new coordinate system are named bx
, by
and bz
. Since the columns of a rotation matrix need to be orthonormal, bx
, by
and bz
need to form an orthonormal set of vectors.
In this case, the original cone is oriented along the z-axis. Since you want the cone to be oriented along (vx, vy, vz)
instead, we use this vector as the z-axis of our new coordinate system. Since we want an orthonormal coordinate system, the only thing left to do to obtain bz
is to normalize this vector:
[vx]
bz = normalize([vy])
[vz]
Since the cone is rotationally symmetrical, it does not really matter how the remaining two base vectors are chosen, just as long as they are both orthogonal to bz
, and orthogonal to each other. A simple way to find an arbitrary orthogonal vector to a given vector is to keep one coordinate 0
, swap the other two coordinates, and change the sign of one of those two coordinates. Again, the vector needs to be normalized. Vectors we could choose with this approach include:
[ vy] [ vz] [ 0 ]
by = normalize([-vx]) by = normalize([ 0 ]) by = normalize([ vz])
[ 0 ] [-vx] [-vy]
The dot product of each of these vectors with (vx, vy, vz)
is zero, which means that the vectors are orthogonal.
While the choice between these (or other variations) is mostly arbitrary, care must be taken to not end up with a degenerate vector. For example if vx
and vy
are both zero, using the first of these vector would be bad. To avoid choosing a (near) degenerate vector, a simple strategy is to use the first of these three vectors if vz
is smaller than both vx
and vy
, and one of the other two otherwise.
With two new base vectors in place, the third is the cross product of the other two:
bx = by x bz
All that's left is to populate the rotation matrix with column vectors bx
, by
and bz
, and the rotation matrix is complete:
[ bx.x by.x bz.x ]
R = [ bx.y by.y bz.y ]
[ bx.z by.z bz.z ]
If you need a 4x4 matrix, e.g. because you are using the legacy fixed function OpenGL pipeline, you can extend this to a 4x4 matrix:
[ bx.x by.x bz.x 0 ]
R = [ bx.y by.y bz.y 0 ]
[ bx.z by.z bz.z 0 ]
[ 0 0 0 1 ]