0

I've been trying to emulate gluLookAt functionality, but with Quaternions. Each of my game object have a TranslationComponent. This component stores the object's position (glm::vec3), rotation (glm::quat) and scale (glm::vec3). The camera calculates its position each tick doing the following:

// UP = glm::vec3(0,1,0); 
//FORWARD = glm::vec3(0,0,1);
cameraPosition = playerPosition - (UP * distanceUP) - (FORWARD * distanceAway);

This position code works as expexted, the camera is place 3 metres behind the player and 1 metre up. Now, the camera's Quaternion is set to the follow:

//Looking at the player's feet  
cameraRotation = quatFromToRotation(FORWARD, playerPosition); 

The rendering engine now takes these values and generates the ViewMatrix (camera) and the ModelMatrix (player) and then renders the scene. The code looks like this:

 glm::mat4 viewTranslationMatrix = 
         glm::translate(glm::mat4(1.0f), cameraTransform->getPosition());
 glm::mat4 viewScaleMatrix = 
         glm::scale(glm::mat4(1.0f), cameraTransform->getScale());
 glm::mat4 viewRotationMatrix = 
         glm::mat4_cast(cameraTransform->getRotation());

 viewMatrix = viewTranslationMatrix * viewRotationMatrix * viewScaleMatrix;

quatFromToRotation(glm::vec3 from, glm::vec3 to) is defined as the following:

glm::quat quatFromToRotation(glm::vec3 from, glm::vec3 to)
{
    from = glm::normalize(from); to = glm::normalize(to);

    float cosTheta = glm::dot(from, to);
    glm::vec3 rotationAxis;

    if (cosTheta < -1 + 0.001f)
    {
        rotationAxis = glm::cross(glm::vec3(0.0f, 0.0f, 1.0f), from);
        if (glm::length2(rotationAxis) < 0.01f)
            rotationAxis = glm::cross(glm::vec3(1.0f, 0.0f, 0.0f), from);

        rotationAxis = glm::normalize(rotationAxis);
        return glm::angleAxis(180.0f, rotationAxis);
    }

    rotationAxis = glm::cross(from, to);

    float s = sqrt((1.0f + cosTheta) * 2.0f);
    float invis = 1.0f / s;

    return glm::quat(
            s * 0.5f,
            rotationAxis.x * invis,
            rotationAxis.y * invis,
            rotationAxis.z * invis
        );
}

What I'm having troubles with is the fact the cameraRotation isn't being set correctly. No matter where the player is, the camera's forward is always (0,0,-1)

genpfault
  • 51,148
  • 11
  • 85
  • 139
Brett
  • 159
  • 1
  • 8
  • Where / how do you compute the camera's `forward`? – Floris Jan 17 '14 at 04:01
  • Assuming `FORWARD` is a direction and not a position, I do not think this is quite what you want... what about `quatToFromRotation (playerPosition + FORWARD, playerPosition);`? – Andon M. Coleman Jan 17 '14 at 04:50
  • Also, the function you listed in your code is `quatFromToRotation (...)`, which is different from what you discussed in the body of your text. – Andon M. Coleman Jan 17 '14 at 04:58
  • Ah, yes, that was a typo. I edited it. – Brett Jan 17 '14 at 05:07
  • Just to note, glm has a function equivalent to `gluLookAt()` in functionality, named `glm::lookAt()` and defined in ``. For more info, check the [glm manual](http://glm.g-truc.net/0.9.5/glm-0.9.5.pdf) and search for "lookAt". You'll find the function documentation there. – chbaker0 Jan 17 '14 at 05:11

1 Answers1

1

Your problem is in the line

//Looking at the player's feet  
cameraRotation = quatToFromRotation(FORWARD, playerPosition);

You need to look from the camera position to the player's feet - not from "one meter above the player" (assuming the player is at (0,0,0) when you initially do this). Replace FORWARD with cameraPosition:

cameraRotation = quatToFromRotation(cameraPosition, playerPosition);

EDIT I believe you have an error in your quatToFromRotation function as well. See https://stackoverflow.com/a/11741520/1967396 for a very nice explanation (and some pseudo code) of quaternion rotation.

Community
  • 1
  • 1
Floris
  • 45,857
  • 6
  • 70
  • 122
  • Doing so will face the camera in some direction that I cannot even tell the orientation. With the player at (0,0,0) and the camera at (0,2,-3) the quaternion is (0.00513127, 0, -0, 0.999987). I'm not vastly experienced with quaternions, so I don't know exactly what this number means. I tried using glm::lookAt while setting the position to the cameras position and the target to the players, and everything worked correctly. Which leads me to believe that `quatFromToRotation` is giving me an incorrect rotation. – Brett Jan 17 '14 at 04:40
  • Quaternions are interesting animals. If you look at the last three elements and normalize them, they are the axis along which you are rotating (almost exactly [0 0 1] but not quite); the angle of rotation is derived by solving cos(theta/2) = q(0) - so theta = 2 * acos(q(0)). I would have expected rotation about the X axis for your geometry, not the Z axis. Where did `quatFromRotation` come from? – Floris Jan 18 '14 at 15:23
  • The rotation was kind of weird, I think you're right and it is against the X axis. Originally, I had wrote the algorithm myself, but I was experiencing a problem relative to this one. So, I decide to use the algorithm here: http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-17-quaternions/#How_do_I_find_the_rotation_between_2_vectors__ – Brett Jan 19 '14 at 07:30