# Problem with Ogre::Camera lookAt function when target is directly below

I am trying to make a class which controls a camera. It's pretty basic right now, it looks like this:

class HoveringCameraController
{
public:

void init(Ogre::Camera & camera, AnimatedBody & target, Ogre::Real height);
void update(Ogre::Real time_delta);
private:
Ogre::Camera * camera_;
AnimatedBody * target_;
Ogre::Real height_;
};


HoveringCameraController.cpp

void HoveringCameraController::init(Ogre::Camera & camera, AnimatedBody & target, Ogre::Real height)
{
camera_ = &camera;
target_ = &target;
height_ = height;

update(0.0);
}

void HoveringCameraController::update(Ogre::Real time_delta)
{
auto position = target_->getPosition();
position.y += height_;
camera_->setPosition(position);
camera_->lookAt(target_->getPosition());
}


AnimatedBody is just a class that encapsulates an entity, it's animations and a scene node. The getPosition function is simply forwarded to it's scene node.

What I want(for now) is for the camera to simply follow the AnimatedBody overhead at the distance given(the height parameter), and look down at it. It follows the object around, but it doesn't look straight down, it's tilted quite a bit in the positive Z direction. Does anybody have any idea why it would do that?

If I change this line:

position.y += height_;


to this:

position.x += height_;


or this:

position.z += height_;


it does exactly what I would expect. It follows the object from the side or front, and looks directly at it.

I believe you are feeling the effects of Gimbal lock. 3D camera implementations typically do not allow for looking directly up or down because of this (because then the forward and up vectors would be parallel). I know from experience that OpenGL can do strange things, and my simple implementation of a camera doesn't allow for less than a 0.1-degree angle up or down.

If you can modify the camera's "up" vector to be something other than (0,0,1), then you should do so when you want to set its forward vector to (0,0,1) (i.e. when you want to look up). The forward and up vectors cannot be the same, though.

Other alternatives include making sure the 'up' vector is orthogonal to the 'forward' vector at all times, or using quaternions. I don't know how these options apply to the Ogre3D engine, sorry.

• +1 for the Quaternion hint. Here's some background info to Ogre3D and Quaternions: ogre3d.org/tikiwiki/…. This post might help too: ogre3d.org/forums/viewtopic.php?p=86862#p86862 Feb 22 '11 at 10:52
• Thanks for the good info. And @bummzack, thanks for that first link. I had heard of quaternions before, but they seemed really confusing. That article cleared things up quite a bit, and it's what lead me to my solution, which I'll post below. Feb 22 '11 at 20:08

I found a simple solution to my problem using quaternions.

const Ogre::Real sqrt_one_half = 0.7071067811865475244; // Square root of 1/2
camera_->setOrientation(Ogre::Quaternion(sqrt_one_half,-sqrt_one_half,0.0,0.0));


Also, why the hell am I setting the rotation every update? I should just do it once in the init function, and then only modify the position in the update function. Here's my updated code, if anyone is interested:

void HoveringCameraController::init(Ogre::Camera & camera, AnimatedBody & target, Ogre::Real height)
{
camera_ = &camera;
target_ = &target;
height_ = height;

auto p = target_->getPosition();
p.y += height_;
camera_->setPosition(p);

const Ogre::Real sqrt_one_half = 0.7071067811865475244; // Square root of 1/2
camera_->setOrientation(Ogre::Quaternion(sqrt_one_half,-sqrt_one_half,0.0,0.0));
}

void HoveringCameraController::update(Ogre::Real time_delta)
{
auto p = target_->getPosition();
p.y += height_;
camera_->setPosition(p);
}

• Though I hate the idea of accepting my own answer, I think this is the clearest, most simple solution(unless someone can come up with a better one). Feb 22 '11 at 20:11