No problem. I wasn't really able to find a useful formula online to use rotations to accomplish the same effect. I did, however, come up with my own formula. I am no math wiz, so the main difficulty I was having was the fact that the camera's rotate methods are all relative to its current orientation (compounded by my lack of experience with 3D geometry). I believe I have finally solved the problem, though.
Here are the two methods for setting camera look-at and up directions using normalized vectors. Note: I've only run some very basic tests on the setUpDirection() method, but it seems to work. I'll write another post here after I've had a chance to use the method more extensively to see if there is an error in my formula.
/**
* Sets the specified Camera's look-at direction.
* @param c Camera to use.
* @param v Normalized vector indicating the look-at direction.
*/
public void setLookDirection( Camera c, SimpleVector v )
{
SimpleVector l = new SimpleVector( v );
l.add( c.getPosition() );
c.lookAt( l );
}
/**
* Sets the specified Camera's up direction.
* @param c Camera to use.
* @param v Normalized vector indicating the up direction.
*/
public void setUpDirection( Camera c, SimpleVector v )
{
SimpleVector previousUp = new SimpleVector( c.getUpVector() );
// TODO: Remove this hack after the next release of jPCT!
previousUp.y = -previousUp.y;
float distance = previousUp.calcSub( v ).length();
float angle = (float) Math.acos( ( 2.0d - (distance * distance) )
/ 2.0d );
if( previousUp.x == -v.x && previousUp.y == -v.y &&
previousUp.z == -v.z )
c.rotateAxis( c.getDirection(), angle );
else
c.rotateAxis( previousUp.calcCross( v ).normalize(), angle );
}
In case you are wondering about that if statement, I put it there to handle the case where the new up-direction is exactly opposite to the previous up-direction (for example, if previous up is -y and new up is y). In such a case, a cross-vector can not be calculated to indicate which axis to rotate around. Also, you may be wondering why I didn't always use c.getDirection() as the axis to rotate around. That is because I am using the law of cosines, which was designed to calculate the angle of a triangle given its sides, so it is limited to angles between 0 and pi. In order to get a full 2 pi of rotation, I calculate the cross-vector, which reverses when the angle becomes greater than pi.